]>
Commit | Line | Data |
---|---|---|
d45ec1de | 1 | /* |
9e9295ed | 2 | * Copyright (C) 2009-2012 Tobias Brunner |
0bd7ad6c | 3 | * Copyright (C) 2005-2009 Martin Willi |
c71d53ba | 4 | * Copyright (C) 2005 Jan Hutter |
d45ec1de MW |
5 | * Hochschule fuer Technik Rapperswil |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2 of the License, or (at your | |
10 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 | * for more details. | |
16 | */ | |
17 | ||
a8c09d8c | 18 | #define _GNU_SOURCE |
d45ec1de MW |
19 | #include <sys/socket.h> |
20 | #include <netinet/in.h> | |
21 | #include <arpa/inet.h> | |
5113680f | 22 | #include <string.h> |
a8c09d8c | 23 | #include <stdio.h> |
d45ec1de MW |
24 | |
25 | #include "identification.h" | |
26 | ||
d3d7e46b | 27 | #include <asn1/oid.h> |
a8c09d8c | 28 | #include <asn1/asn1.h> |
930443af | 29 | #include <crypto/hashers/hasher.h> |
a8c09d8c | 30 | |
552cc11b MW |
31 | ENUM_BEGIN(id_match_names, ID_MATCH_NONE, ID_MATCH_MAX_WILDCARDS, |
32 | "MATCH_NONE", | |
33 | "MATCH_ANY", | |
34 | "MATCH_MAX_WILDCARDS"); | |
35 | ENUM_NEXT(id_match_names, ID_MATCH_PERFECT, ID_MATCH_PERFECT, ID_MATCH_MAX_WILDCARDS, | |
36 | "MATCH_PERFECT"); | |
37 | ENUM_END(id_match_names, ID_MATCH_PERFECT); | |
38 | ||
60356f33 | 39 | ENUM_BEGIN(id_type_names, ID_ANY, ID_KEY_ID, |
40f29769 AS |
40 | "ID_ANY", |
41 | "ID_IPV4_ADDR", | |
42 | "ID_FQDN", | |
43 | "ID_RFC822_ADDR", | |
44 | "ID_IPV4_ADDR_SUBNET", | |
45 | "ID_IPV6_ADDR", | |
46 | "ID_IPV6_ADDR_SUBNET", | |
47 | "ID_IPV4_ADDR_RANGE", | |
48 | "ID_IPV6_ADDR_RANGE", | |
49 | "ID_DER_ASN1_DN", | |
50 | "ID_DER_ASN1_GN", | |
60356f33 | 51 | "ID_KEY_ID"); |
c88104aa | 52 | ENUM_NEXT(id_type_names, ID_DER_ASN1_GN_URI, ID_USER_ID, ID_KEY_ID, |
4172574b | 53 | "ID_DER_ASN1_GN_URI", |
c88104aa AS |
54 | "ID_USER_ID"); |
55 | ENUM_END(id_type_names, ID_USER_ID); | |
40f29769 | 56 | |
a8c09d8c | 57 | /** |
7daf5226 | 58 | * coding of X.501 distinguished name |
a8c09d8c MW |
59 | */ |
60 | typedef struct { | |
61 | const u_char *name; | |
c31687da | 62 | int oid; |
a8c09d8c MW |
63 | u_char type; |
64 | } x501rdn_t; | |
65 | ||
66 | static const x501rdn_t x501rdns[] = { | |
a30e0259 AS |
67 | {"ND", OID_NAME_DISTINGUISHER, ASN1_PRINTABLESTRING}, |
68 | {"UID", OID_PILOT_USERID, ASN1_PRINTABLESTRING}, | |
69 | {"DC", OID_PILOT_DOMAIN_COMPONENT, ASN1_PRINTABLESTRING}, | |
70 | {"CN", OID_COMMON_NAME, ASN1_PRINTABLESTRING}, | |
71 | {"S", OID_SURNAME, ASN1_PRINTABLESTRING}, | |
72 | {"SN", OID_SERIAL_NUMBER, ASN1_PRINTABLESTRING}, | |
73 | {"serialNumber", OID_SERIAL_NUMBER, ASN1_PRINTABLESTRING}, | |
74 | {"C", OID_COUNTRY, ASN1_PRINTABLESTRING}, | |
75 | {"L", OID_LOCALITY, ASN1_PRINTABLESTRING}, | |
76 | {"ST", OID_STATE_OR_PROVINCE, ASN1_PRINTABLESTRING}, | |
77 | {"O", OID_ORGANIZATION, ASN1_PRINTABLESTRING}, | |
78 | {"OU", OID_ORGANIZATION_UNIT, ASN1_PRINTABLESTRING}, | |
79 | {"T", OID_TITLE, ASN1_PRINTABLESTRING}, | |
80 | {"D", OID_DESCRIPTION, ASN1_PRINTABLESTRING}, | |
81 | {"N", OID_NAME, ASN1_PRINTABLESTRING}, | |
82 | {"G", OID_GIVEN_NAME, ASN1_PRINTABLESTRING}, | |
83 | {"I", OID_INITIALS, ASN1_PRINTABLESTRING}, | |
ef511fc0 | 84 | {"dnQualifier", OID_DN_QUALIFIER, ASN1_PRINTABLESTRING}, |
a30e0259 AS |
85 | {"ID", OID_UNIQUE_IDENTIFIER, ASN1_PRINTABLESTRING}, |
86 | {"EN", OID_EMPLOYEE_NUMBER, ASN1_PRINTABLESTRING}, | |
87 | {"employeeNumber", OID_EMPLOYEE_NUMBER, ASN1_PRINTABLESTRING}, | |
88 | {"E", OID_EMAIL_ADDRESS, ASN1_IA5STRING}, | |
89 | {"Email", OID_EMAIL_ADDRESS, ASN1_IA5STRING}, | |
90 | {"emailAddress", OID_EMAIL_ADDRESS, ASN1_IA5STRING}, | |
91 | {"UN", OID_UNSTRUCTURED_NAME, ASN1_IA5STRING}, | |
92 | {"unstructuredName", OID_UNSTRUCTURED_NAME, ASN1_IA5STRING}, | |
93 | {"UA", OID_UNSTRUCTURED_ADDRESS, ASN1_PRINTABLESTRING}, | |
94 | {"unstructuredAddress", OID_UNSTRUCTURED_ADDRESS, ASN1_PRINTABLESTRING}, | |
95 | {"TCGID", OID_TCGID, ASN1_PRINTABLESTRING} | |
a8c09d8c | 96 | }; |
a8c09d8c | 97 | |
a8c09d8c | 98 | /** |
353c7b57 | 99 | * maximum number of RDNs in atodn() |
a8c09d8c | 100 | */ |
353c7b57 | 101 | #define RDN_MAX 20 |
a8c09d8c | 102 | |
a8c09d8c | 103 | |
d45ec1de MW |
104 | typedef struct private_identification_t private_identification_t; |
105 | ||
106 | /** | |
107 | * Private data of an identification_t object. | |
108 | */ | |
109 | struct private_identification_t { | |
110 | /** | |
111 | * Public interface. | |
112 | */ | |
113 | identification_t public; | |
7daf5226 | 114 | |
d45ec1de | 115 | /** |
d794bcdb | 116 | * Encoded representation of this ID. |
d45ec1de MW |
117 | */ |
118 | chunk_t encoded; | |
7daf5226 | 119 | |
d45ec1de | 120 | /** |
d794bcdb | 121 | * Type of this ID. |
d45ec1de MW |
122 | */ |
123 | id_type_t type; | |
124 | }; | |
125 | ||
6bdd79d8 MW |
126 | /** |
127 | * Enumerator over RDNs | |
128 | */ | |
129 | typedef struct { | |
130 | /* implements enumerator interface */ | |
131 | enumerator_t public; | |
3d2f73b9 MW |
132 | /* next set to parse, if any */ |
133 | chunk_t sets; | |
134 | /* next sequence in set, if any */ | |
135 | chunk_t seqs; | |
6bdd79d8 MW |
136 | } rdn_enumerator_t; |
137 | ||
2fcb2cc6 MW |
138 | METHOD(enumerator_t, rdn_enumerate, bool, |
139 | rdn_enumerator_t *this, chunk_t *oid, u_char *type, chunk_t *data) | |
6bdd79d8 MW |
140 | { |
141 | chunk_t rdn; | |
7daf5226 | 142 | |
3d2f73b9 MW |
143 | /* a DN contains one or more SET, each containing one or more SEQUENCES, |
144 | * each containing a OID/value RDN */ | |
145 | if (!this->seqs.len) | |
6bdd79d8 | 146 | { |
3d2f73b9 MW |
147 | /* no SEQUENCEs in current SET, parse next SET */ |
148 | if (asn1_unwrap(&this->sets, &this->seqs) != ASN1_SET) | |
6bdd79d8 | 149 | { |
3d2f73b9 MW |
150 | return FALSE; |
151 | } | |
152 | } | |
153 | if (asn1_unwrap(&this->seqs, &rdn) == ASN1_SEQUENCE && | |
154 | asn1_unwrap(&rdn, oid) == ASN1_OID) | |
155 | { | |
156 | int t = asn1_unwrap(&rdn, data); | |
7daf5226 | 157 | |
3d2f73b9 MW |
158 | if (t != ASN1_INVALID) |
159 | { | |
160 | *type = t; | |
161 | return TRUE; | |
6bdd79d8 MW |
162 | } |
163 | } | |
164 | return FALSE; | |
165 | } | |
166 | ||
167 | /** | |
168 | * Create an enumerator over all RDNs (oid, string type, data) of a DN | |
169 | */ | |
170 | static enumerator_t* create_rdn_enumerator(chunk_t dn) | |
171 | { | |
2fcb2cc6 | 172 | rdn_enumerator_t *e; |
7daf5226 | 173 | |
2fcb2cc6 MW |
174 | INIT(e, |
175 | .public = { | |
176 | .enumerate = (void*)_rdn_enumerate, | |
177 | .destroy = (void*)free, | |
178 | }, | |
179 | ); | |
7daf5226 | 180 | |
3d2f73b9 MW |
181 | /* a DN is a SEQUENCE, get the first SET of it */ |
182 | if (asn1_unwrap(&dn, &e->sets) == ASN1_SEQUENCE) | |
6bdd79d8 | 183 | { |
3d2f73b9 | 184 | e->seqs = chunk_empty; |
6bdd79d8 MW |
185 | return &e->public; |
186 | } | |
ed680e33 | 187 | free(e); |
6bdd79d8 MW |
188 | return enumerator_create_empty(); |
189 | } | |
190 | ||
191 | /** | |
192 | * Part enumerator over RDNs | |
193 | */ | |
194 | typedef struct { | |
195 | /* implements enumerator interface */ | |
196 | enumerator_t public; | |
197 | /* inner RDN enumerator */ | |
198 | enumerator_t *inner; | |
199 | } rdn_part_enumerator_t; | |
200 | ||
2fcb2cc6 MW |
201 | METHOD(enumerator_t, rdn_part_enumerate, bool, |
202 | rdn_part_enumerator_t *this, id_part_t *type, chunk_t *data) | |
6bdd79d8 MW |
203 | { |
204 | int i, known_oid, strtype; | |
205 | chunk_t oid, inner_data; | |
206 | static const struct { | |
207 | int oid; | |
208 | id_part_t type; | |
209 | } oid2part[] = { | |
210 | {OID_COMMON_NAME, ID_PART_RDN_CN}, | |
211 | {OID_SURNAME, ID_PART_RDN_S}, | |
212 | {OID_SERIAL_NUMBER, ID_PART_RDN_SN}, | |
213 | {OID_COUNTRY, ID_PART_RDN_C}, | |
214 | {OID_LOCALITY, ID_PART_RDN_L}, | |
215 | {OID_STATE_OR_PROVINCE, ID_PART_RDN_ST}, | |
216 | {OID_ORGANIZATION, ID_PART_RDN_O}, | |
217 | {OID_ORGANIZATION_UNIT, ID_PART_RDN_OU}, | |
218 | {OID_TITLE, ID_PART_RDN_T}, | |
219 | {OID_DESCRIPTION, ID_PART_RDN_D}, | |
220 | {OID_NAME, ID_PART_RDN_N}, | |
221 | {OID_GIVEN_NAME, ID_PART_RDN_G}, | |
222 | {OID_INITIALS, ID_PART_RDN_I}, | |
ef511fc0 | 223 | {OID_DN_QUALIFIER, ID_PART_RDN_DNQ}, |
6bdd79d8 MW |
224 | {OID_UNIQUE_IDENTIFIER, ID_PART_RDN_ID}, |
225 | {OID_EMAIL_ADDRESS, ID_PART_RDN_E}, | |
226 | {OID_EMPLOYEE_NUMBER, ID_PART_RDN_EN}, | |
227 | }; | |
7daf5226 | 228 | |
6bdd79d8 MW |
229 | while (this->inner->enumerate(this->inner, &oid, &strtype, &inner_data)) |
230 | { | |
231 | known_oid = asn1_known_oid(oid); | |
232 | for (i = 0; i < countof(oid2part); i++) | |
233 | { | |
234 | if (oid2part[i].oid == known_oid) | |
235 | { | |
236 | *type = oid2part[i].type; | |
237 | *data = inner_data; | |
238 | return TRUE; | |
239 | } | |
240 | } | |
241 | } | |
242 | return FALSE; | |
243 | } | |
244 | ||
2fcb2cc6 MW |
245 | METHOD(enumerator_t, rdn_part_enumerator_destroy, void, |
246 | rdn_part_enumerator_t *this) | |
6bdd79d8 MW |
247 | { |
248 | this->inner->destroy(this->inner); | |
249 | free(this); | |
250 | } | |
251 | ||
2fcb2cc6 MW |
252 | METHOD(identification_t, create_part_enumerator, enumerator_t*, |
253 | private_identification_t *this) | |
6bdd79d8 MW |
254 | { |
255 | switch (this->type) | |
256 | { | |
257 | case ID_DER_ASN1_DN: | |
258 | { | |
2fcb2cc6 MW |
259 | rdn_part_enumerator_t *e; |
260 | ||
261 | INIT(e, | |
262 | .inner = create_rdn_enumerator(this->encoded), | |
263 | .public = { | |
264 | .enumerate = (void*)_rdn_part_enumerate, | |
265 | .destroy = _rdn_part_enumerator_destroy, | |
266 | }, | |
267 | ); | |
6bdd79d8 MW |
268 | return &e->public; |
269 | } | |
270 | case ID_RFC822_ADDR: | |
271 | /* TODO */ | |
272 | case ID_FQDN: | |
273 | /* TODO */ | |
274 | default: | |
275 | return enumerator_create_empty(); | |
276 | } | |
277 | } | |
278 | ||
f00c3506 TB |
279 | /** |
280 | * Print a separator between two RDNs | |
281 | */ | |
282 | static inline bool print_separator(char **buf, size_t *len) | |
283 | { | |
284 | int written; | |
285 | ||
286 | written = snprintf(*buf, *len, ", "); | |
287 | if (written < 0 || written >= *len) | |
288 | { | |
289 | return FALSE; | |
290 | } | |
291 | *buf += written; | |
292 | *len -= written; | |
293 | return TRUE; | |
294 | } | |
295 | ||
a8c09d8c | 296 | /** |
8309798f | 297 | * Print a DN with all its RDN in a buffer to present it to the user |
a8c09d8c | 298 | */ |
8309798f | 299 | static void dntoa(chunk_t dn, char *buf, size_t len) |
a8c09d8c | 300 | { |
8309798f | 301 | enumerator_t *e; |
fef3b0b7 | 302 | chunk_t oid_data, data, printable; |
8309798f MW |
303 | u_char type; |
304 | int oid, written; | |
7721fc66 | 305 | bool finished = FALSE, empty = TRUE; |
7daf5226 | 306 | |
8309798f MW |
307 | e = create_rdn_enumerator(dn); |
308 | while (e->enumerate(e, &oid_data, &type, &data)) | |
a8c09d8c | 309 | { |
7721fc66 MW |
310 | empty = FALSE; |
311 | ||
f00c3506 TB |
312 | /* previous RDN was empty but it wasn't the last one */ |
313 | if (finished && !print_separator(&buf, &len)) | |
314 | { | |
315 | break; | |
316 | } | |
317 | finished = FALSE; | |
7daf5226 | 318 | |
f00c3506 | 319 | oid = asn1_known_oid(oid_data); |
8309798f | 320 | if (oid == OID_UNKNOWN) |
552cc11b | 321 | { |
8309798f | 322 | written = snprintf(buf, len, "%#B=", &oid_data); |
552cc11b | 323 | } |
8309798f MW |
324 | else |
325 | { | |
326 | written = snprintf(buf, len,"%s=", oid_names[oid].name); | |
327 | } | |
018543f3 MW |
328 | if (written < 0 || written >= len) |
329 | { | |
330 | break; | |
331 | } | |
8309798f MW |
332 | buf += written; |
333 | len -= written; | |
7daf5226 | 334 | |
5e75f50b | 335 | written = 0; |
fef3b0b7 | 336 | chunk_printable(data, &printable, '?'); |
5e75f50b TB |
337 | if (printable.ptr) |
338 | { | |
339 | written = snprintf(buf, len, "%.*s", (int)printable.len, | |
340 | printable.ptr); | |
341 | } | |
fef3b0b7 | 342 | chunk_free(&printable); |
018543f3 MW |
343 | if (written < 0 || written >= len) |
344 | { | |
345 | break; | |
346 | } | |
8309798f MW |
347 | buf += written; |
348 | len -= written; | |
7daf5226 | 349 | |
f00c3506 TB |
350 | if (!data.ptr) |
351 | { /* we can't calculate if we're finished, assume we are */ | |
352 | finished = TRUE; | |
a8c09d8c | 353 | } |
f00c3506 | 354 | else if (data.ptr + data.len == dn.ptr + dn.len) |
a8c09d8c | 355 | { |
8309798f MW |
356 | finished = TRUE; |
357 | break; | |
a8c09d8c | 358 | } |
f00c3506 TB |
359 | else if (!print_separator(&buf, &len)) |
360 | { | |
361 | break; | |
362 | } | |
a8c09d8c | 363 | } |
7721fc66 MW |
364 | if (empty) |
365 | { | |
366 | snprintf(buf, len, ""); | |
367 | } | |
368 | else if (!finished) | |
8309798f MW |
369 | { |
370 | snprintf(buf, len, "(invalid ID_DER_ASN1_DN)"); | |
371 | } | |
372 | e->destroy(e); | |
a8c09d8c MW |
373 | } |
374 | ||
a8c09d8c MW |
375 | /** |
376 | * Converts an LDAP-style human-readable ASCII-encoded | |
377 | * ASN.1 distinguished name into binary DER-encoded format | |
378 | */ | |
379 | static status_t atodn(char *src, chunk_t *dn) | |
380 | { | |
381 | /* finite state machine for atodn */ | |
382 | typedef enum { | |
383 | SEARCH_OID = 0, | |
384 | READ_OID = 1, | |
385 | SEARCH_NAME = 2, | |
386 | READ_NAME = 3, | |
387 | UNKNOWN_OID = 4 | |
388 | } state_t; | |
7daf5226 | 389 | |
db7ef624 MW |
390 | chunk_t oid = chunk_empty; |
391 | chunk_t name = chunk_empty; | |
353c7b57 AS |
392 | chunk_t rdns[RDN_MAX]; |
393 | int rdn_count = 0; | |
394 | int dn_len = 0; | |
a8c09d8c | 395 | int whitespace = 0; |
2fcc4168 | 396 | int i = 0; |
a8c09d8c MW |
397 | asn1_t rdn_type; |
398 | state_t state = SEARCH_OID; | |
399 | status_t status = SUCCESS; | |
7daf5226 | 400 | |
a8c09d8c MW |
401 | do |
402 | { | |
403 | switch (state) | |
404 | { | |
405 | case SEARCH_OID: | |
b1abf22b | 406 | if (*src != ' ' && *src != '/' && *src != ',' && *src != '\0') |
a8c09d8c MW |
407 | { |
408 | oid.ptr = src; | |
409 | oid.len = 1; | |
410 | state = READ_OID; | |
411 | } | |
412 | break; | |
413 | case READ_OID: | |
414 | if (*src != ' ' && *src != '=') | |
415 | { | |
416 | oid.len++; | |
417 | } | |
418 | else | |
419 | { | |
c31687da | 420 | bool found = FALSE; |
7daf5226 | 421 | |
c31687da | 422 | for (i = 0; i < countof(x501rdns); i++) |
a8c09d8c | 423 | { |
c31687da MW |
424 | if (strlen(x501rdns[i].name) == oid.len && |
425 | strncasecmp(x501rdns[i].name, oid.ptr, oid.len) == 0) | |
a8c09d8c | 426 | { |
c31687da MW |
427 | found = TRUE; |
428 | break; | |
a8c09d8c MW |
429 | } |
430 | } | |
c31687da | 431 | if (!found) |
a8c09d8c MW |
432 | { |
433 | status = NOT_SUPPORTED; | |
434 | state = UNKNOWN_OID; | |
435 | break; | |
436 | } | |
437 | /* reset oid and change state */ | |
db7ef624 | 438 | oid = chunk_empty; |
a8c09d8c MW |
439 | state = SEARCH_NAME; |
440 | } | |
441 | break; | |
442 | case SEARCH_NAME: | |
9e9295ed TB |
443 | if (*src == ' ' || *src == '=') |
444 | { | |
445 | break; | |
446 | } | |
10584df2 | 447 | else if (*src != ',' && *src != '/' && *src != '\0') |
a8c09d8c MW |
448 | { |
449 | name.ptr = src; | |
450 | name.len = 1; | |
451 | whitespace = 0; | |
452 | state = READ_NAME; | |
9e9295ed | 453 | break; |
a8c09d8c | 454 | } |
9e9295ed TB |
455 | name = chunk_empty; |
456 | whitespace = 0; | |
457 | state = READ_NAME; | |
458 | /* fall-through */ | |
a8c09d8c MW |
459 | case READ_NAME: |
460 | if (*src != ',' && *src != '/' && *src != '\0') | |
461 | { | |
462 | name.len++; | |
463 | if (*src == ' ') | |
a8c09d8c | 464 | whitespace++; |
a8c09d8c | 465 | else |
a8c09d8c | 466 | whitespace = 0; |
a8c09d8c MW |
467 | } |
468 | else | |
469 | { | |
470 | name.len -= whitespace; | |
353c7b57 | 471 | rdn_type = (x501rdns[i].type == ASN1_PRINTABLESTRING |
d3d7e46b AS |
472 | && !asn1_is_printablestring(name)) |
473 | ? ASN1_T61STRING : x501rdns[i].type; | |
7daf5226 | 474 | |
353c7b57 | 475 | if (rdn_count < RDN_MAX) |
a8c09d8c | 476 | { |
c31687da | 477 | chunk_t rdn_oid; |
7daf5226 | 478 | |
cfa42285 | 479 | rdn_oid = asn1_build_known_oid(x501rdns[i].oid); |
c31687da MW |
480 | if (rdn_oid.len) |
481 | { | |
7daf5226 | 482 | rdns[rdn_count] = |
c31687da MW |
483 | asn1_wrap(ASN1_SET, "m", |
484 | asn1_wrap(ASN1_SEQUENCE, "mm", | |
cfa42285 | 485 | rdn_oid, |
c31687da MW |
486 | asn1_wrap(rdn_type, "c", name) |
487 | ) | |
488 | ); | |
489 | dn_len += rdns[rdn_count++].len; | |
490 | } | |
491 | else | |
492 | { | |
493 | status = INVALID_ARG; | |
494 | } | |
a8c09d8c MW |
495 | } |
496 | else | |
497 | { | |
498 | status = OUT_OF_RES; | |
499 | } | |
500 | /* reset name and change state */ | |
db7ef624 | 501 | name = chunk_empty; |
a8c09d8c MW |
502 | state = SEARCH_OID; |
503 | } | |
504 | break; | |
505 | case UNKNOWN_OID: | |
506 | break; | |
507 | } | |
508 | } while (*src++ != '\0'); | |
7daf5226 | 509 | |
b1abf22b TB |
510 | if (state == READ_OID) |
511 | { /* unterminated OID */ | |
512 | status = INVALID_ARG; | |
513 | } | |
514 | ||
a8c09d8c | 515 | /* build the distinguished name sequence */ |
c31687da | 516 | { |
353c7b57 | 517 | int i; |
d3d7e46b | 518 | u_char *pos = asn1_build_object(dn, ASN1_SEQUENCE, dn_len); |
7daf5226 | 519 | |
353c7b57 AS |
520 | for (i = 0; i < rdn_count; i++) |
521 | { | |
7daf5226 | 522 | memcpy(pos, rdns[i].ptr, rdns[i].len); |
353c7b57 AS |
523 | pos += rdns[i].len; |
524 | free(rdns[i].ptr); | |
525 | } | |
526 | } | |
a8c09d8c MW |
527 | if (status != SUCCESS) |
528 | { | |
529 | free(dn->ptr); | |
db7ef624 | 530 | *dn = chunk_empty; |
a8c09d8c MW |
531 | } |
532 | return status; | |
533 | } | |
534 | ||
2fcb2cc6 MW |
535 | METHOD(identification_t, get_encoding, chunk_t, |
536 | private_identification_t *this) | |
d45ec1de MW |
537 | { |
538 | return this->encoded; | |
539 | } | |
540 | ||
2fcb2cc6 MW |
541 | METHOD(identification_t, get_type, id_type_t, |
542 | private_identification_t *this) | |
d45ec1de MW |
543 | { |
544 | return this->type; | |
545 | } | |
d45ec1de | 546 | |
2fcb2cc6 MW |
547 | METHOD(identification_t, contains_wildcards_dn, bool, |
548 | private_identification_t *this) | |
e82c3695 | 549 | { |
01da687f MW |
550 | enumerator_t *enumerator; |
551 | bool contains = FALSE; | |
552 | id_part_t type; | |
553 | chunk_t data; | |
7daf5226 | 554 | |
01da687f MW |
555 | enumerator = create_part_enumerator(this); |
556 | while (enumerator->enumerate(enumerator, &type, &data)) | |
e82c3695 | 557 | { |
01da687f | 558 | if (data.len == 1 && data.ptr[0] == '*') |
e82c3695 | 559 | { |
01da687f MW |
560 | contains = TRUE; |
561 | break; | |
e82c3695 MW |
562 | } |
563 | } | |
01da687f MW |
564 | enumerator->destroy(enumerator); |
565 | return contains; | |
e82c3695 MW |
566 | } |
567 | ||
2fcb2cc6 MW |
568 | METHOD(identification_t, contains_wildcards_memchr, bool, |
569 | private_identification_t *this) | |
eea35346 | 570 | { |
0c31b9db | 571 | return memchr(this->encoded.ptr, '*', this->encoded.len) != NULL; |
eea35346 MW |
572 | } |
573 | ||
2fcb2cc6 MW |
574 | METHOD(identification_t, equals_binary, bool, |
575 | private_identification_t *this, identification_t *other) | |
a9428251 | 576 | { |
2fcb2cc6 | 577 | if (this->type == other->get_type(other)) |
f925b42a MW |
578 | { |
579 | if (this->type == ID_ANY) | |
580 | { | |
581 | return TRUE; | |
582 | } | |
2fcb2cc6 | 583 | return chunk_equals(this->encoded, other->get_encoding(other)); |
f925b42a | 584 | } |
2d00984d | 585 | return FALSE; |
a9428251 JH |
586 | } |
587 | ||
d6925572 MW |
588 | /** |
589 | * Compare to DNs, for equality if wc == NULL, for match otherwise | |
590 | */ | |
591 | static bool compare_dn(chunk_t t_dn, chunk_t o_dn, int *wc) | |
592 | { | |
593 | enumerator_t *t, *o; | |
594 | chunk_t t_oid, o_oid, t_data, o_data; | |
595 | u_char t_type, o_type; | |
596 | bool t_next, o_next, finished = FALSE; | |
7daf5226 | 597 | |
d6925572 MW |
598 | if (wc) |
599 | { | |
600 | *wc = 0; | |
601 | } | |
602 | else | |
603 | { | |
604 | if (t_dn.len != o_dn.len) | |
605 | { | |
606 | return FALSE; | |
607 | } | |
608 | } | |
609 | /* try a binary compare */ | |
7f4a13ff | 610 | if (chunk_equals(t_dn, o_dn)) |
d6925572 MW |
611 | { |
612 | return TRUE; | |
613 | } | |
7daf5226 | 614 | |
d6925572 MW |
615 | t = create_rdn_enumerator(t_dn); |
616 | o = create_rdn_enumerator(o_dn); | |
617 | while (TRUE) | |
618 | { | |
619 | t_next = t->enumerate(t, &t_oid, &t_type, &t_data); | |
620 | o_next = o->enumerate(o, &o_oid, &o_type, &o_data); | |
7daf5226 | 621 | |
d6925572 MW |
622 | if (!o_next && !t_next) |
623 | { | |
624 | break; | |
625 | } | |
626 | finished = FALSE; | |
627 | if (o_next != t_next) | |
628 | { | |
629 | break; | |
630 | } | |
631 | if (!chunk_equals(t_oid, o_oid)) | |
632 | { | |
633 | break; | |
634 | } | |
635 | if (wc && o_data.len == 1 && o_data.ptr[0] == '*') | |
636 | { | |
637 | (*wc)++; | |
638 | } | |
639 | else | |
640 | { | |
641 | if (t_data.len != o_data.len) | |
642 | { | |
643 | break; | |
644 | } | |
645 | if (t_type == o_type && | |
646 | (t_type == ASN1_PRINTABLESTRING || | |
647 | (t_type == ASN1_IA5STRING && | |
fc0ed07c | 648 | asn1_known_oid(t_oid) == OID_EMAIL_ADDRESS))) |
d6925572 MW |
649 | { /* ignore case for printableStrings and email RDNs */ |
650 | if (strncasecmp(t_data.ptr, o_data.ptr, t_data.len) != 0) | |
651 | { | |
652 | break; | |
653 | } | |
654 | } | |
655 | else | |
656 | { /* respect case and length for everything else */ | |
657 | if (!memeq(t_data.ptr, o_data.ptr, t_data.len)) | |
658 | { | |
659 | break; | |
660 | } | |
661 | } | |
662 | } | |
663 | /* the enumerator returns FALSE on parse error, we are finished | |
664 | * if we have reached the end of the DN only */ | |
665 | if ((t_data.ptr + t_data.len == t_dn.ptr + t_dn.len) && | |
666 | (o_data.ptr + o_data.len == o_dn.ptr + o_dn.len)) | |
667 | { | |
668 | finished = TRUE; | |
669 | } | |
670 | } | |
671 | t->destroy(t); | |
672 | o->destroy(o); | |
673 | return finished; | |
674 | } | |
675 | ||
2fcb2cc6 MW |
676 | METHOD(identification_t, equals_dn, bool, |
677 | private_identification_t *this, identification_t *other) | |
87a217f9 | 678 | { |
2fcb2cc6 | 679 | return compare_dn(this->encoded, other->get_encoding(other), NULL); |
a8c09d8c MW |
680 | } |
681 | ||
2fcb2cc6 MW |
682 | METHOD(identification_t, equals_strcasecmp, bool, |
683 | private_identification_t *this, identification_t *other) | |
eda454a2 | 684 | { |
2fcb2cc6 MW |
685 | chunk_t encoded = other->get_encoding(other); |
686 | ||
7daf5226 | 687 | /* we do some extra sanity checks to check for invalid IDs with a |
eda454a2 | 688 | * terminating null in it. */ |
2fcb2cc6 | 689 | if (this->encoded.len == encoded.len && |
eda454a2 | 690 | memchr(this->encoded.ptr, 0, this->encoded.len) == NULL && |
2fcb2cc6 MW |
691 | memchr(encoded.ptr, 0, encoded.len) == NULL && |
692 | strncasecmp(this->encoded.ptr, encoded.ptr, this->encoded.len) == 0) | |
eda454a2 MW |
693 | { |
694 | return TRUE; | |
695 | } | |
696 | return FALSE; | |
697 | } | |
698 | ||
2fcb2cc6 MW |
699 | METHOD(identification_t, matches_binary, id_match_t, |
700 | private_identification_t *this, identification_t *other) | |
151168f6 | 701 | { |
2fcb2cc6 | 702 | if (other->get_type(other) == ID_ANY) |
1c32a71e | 703 | { |
552cc11b | 704 | return ID_MATCH_ANY; |
1c32a71e | 705 | } |
2fcb2cc6 MW |
706 | if (this->type == other->get_type(other) && |
707 | chunk_equals(this->encoded, other->get_encoding(other))) | |
c60c7694 | 708 | { |
552cc11b | 709 | return ID_MATCH_PERFECT; |
c60c7694 | 710 | } |
552cc11b | 711 | return ID_MATCH_NONE; |
40f29769 AS |
712 | } |
713 | ||
2fcb2cc6 MW |
714 | METHOD(identification_t, matches_string, id_match_t, |
715 | private_identification_t *this, identification_t *other) | |
a8c09d8c | 716 | { |
2fcb2cc6 MW |
717 | chunk_t encoded = other->get_encoding(other); |
718 | u_int len = encoded.len; | |
7daf5226 | 719 | |
2fcb2cc6 | 720 | if (other->get_type(other) == ID_ANY) |
eea35346 | 721 | { |
552cc11b | 722 | return ID_MATCH_ANY; |
eea35346 | 723 | } |
2fcb2cc6 | 724 | if (this->type != other->get_type(other)) |
552cc11b MW |
725 | { |
726 | return ID_MATCH_NONE; | |
727 | } | |
eab63e84 MW |
728 | /* try a equals check first */ |
729 | if (equals_strcasecmp(this, other)) | |
87a217f9 | 730 | { |
552cc11b | 731 | return ID_MATCH_PERFECT; |
87a217f9 | 732 | } |
40f29769 | 733 | if (len == 0 || this->encoded.len < len) |
552cc11b MW |
734 | { |
735 | return ID_MATCH_NONE; | |
736 | } | |
40f29769 AS |
737 | |
738 | /* check for single wildcard at the head of the string */ | |
2fcb2cc6 | 739 | if (*encoded.ptr == '*') |
87a217f9 | 740 | { |
40f29769 AS |
741 | /* single asterisk matches any string */ |
742 | if (len-- == 1) | |
552cc11b MW |
743 | { /* not better than ID_ANY */ |
744 | return ID_MATCH_ANY; | |
745 | } | |
7daf5226 | 746 | if (strncasecmp(this->encoded.ptr + this->encoded.len - len, |
2fcb2cc6 | 747 | encoded.ptr + 1, len) == 0) |
552cc11b MW |
748 | { |
749 | return ID_MATCH_ONE_WILDCARD; | |
750 | } | |
a8c09d8c | 751 | } |
552cc11b | 752 | return ID_MATCH_NONE; |
a8c09d8c MW |
753 | } |
754 | ||
2fcb2cc6 MW |
755 | METHOD(identification_t, matches_any, id_match_t, |
756 | private_identification_t *this, identification_t *other) | |
151168f6 | 757 | { |
2fcb2cc6 | 758 | if (other->get_type(other) == ID_ANY) |
c60c7694 | 759 | { |
552cc11b | 760 | return ID_MATCH_ANY; |
c60c7694 | 761 | } |
552cc11b | 762 | return ID_MATCH_NONE; |
a8c09d8c MW |
763 | } |
764 | ||
2fcb2cc6 MW |
765 | METHOD(identification_t, matches_dn, id_match_t, |
766 | private_identification_t *this, identification_t *other) | |
a8c09d8c | 767 | { |
552cc11b | 768 | int wc; |
7daf5226 | 769 | |
2fcb2cc6 | 770 | if (other->get_type(other) == ID_ANY) |
eea35346 | 771 | { |
552cc11b | 772 | return ID_MATCH_ANY; |
eea35346 | 773 | } |
7daf5226 | 774 | |
2fcb2cc6 | 775 | if (this->type == other->get_type(other)) |
a8c09d8c | 776 | { |
2fcb2cc6 | 777 | if (compare_dn(this->encoded, other->get_encoding(other), &wc)) |
552cc11b | 778 | { |
d6925572 | 779 | wc = min(wc, ID_MATCH_ONE_WILDCARD - ID_MATCH_MAX_WILDCARDS); |
552cc11b MW |
780 | return ID_MATCH_PERFECT - wc; |
781 | } | |
87a217f9 | 782 | } |
552cc11b | 783 | return ID_MATCH_NONE; |
87a217f9 MW |
784 | } |
785 | ||
151168f6 | 786 | /** |
d25ce370 | 787 | * Described in header. |
151168f6 | 788 | */ |
1b40b74d MW |
789 | int identification_printf_hook(printf_hook_data_t *data, |
790 | printf_hook_spec_t *spec, const void *const *args) | |
151168f6 MW |
791 | { |
792 | private_identification_t *this = *((private_identification_t**)(args[0])); | |
8309798f MW |
793 | chunk_t proper; |
794 | char buf[512]; | |
7daf5226 | 795 | |
151168f6 MW |
796 | if (this == NULL) |
797 | { | |
1b40b74d | 798 | return print_in_hook(data, "%*s", spec->width, "(null)"); |
151168f6 | 799 | } |
7daf5226 | 800 | |
151168f6 MW |
801 | switch (this->type) |
802 | { | |
803 | case ID_ANY: | |
9f9903a3 MW |
804 | snprintf(buf, sizeof(buf), "%%any"); |
805 | break; | |
151168f6 MW |
806 | case ID_IPV4_ADDR: |
807 | if (this->encoded.len < sizeof(struct in_addr) || | |
808 | inet_ntop(AF_INET, this->encoded.ptr, buf, sizeof(buf)) == NULL) | |
809 | { | |
9f9903a3 | 810 | snprintf(buf, sizeof(buf), "(invalid ID_IPV4_ADDR)"); |
151168f6 | 811 | } |
9f9903a3 | 812 | break; |
151168f6 MW |
813 | case ID_IPV6_ADDR: |
814 | if (this->encoded.len < sizeof(struct in6_addr) || | |
815 | inet_ntop(AF_INET6, this->encoded.ptr, buf, INET6_ADDRSTRLEN) == NULL) | |
816 | { | |
9f9903a3 | 817 | snprintf(buf, sizeof(buf), "(invalid ID_IPV6_ADDR)"); |
151168f6 | 818 | } |
9f9903a3 | 819 | break; |
151168f6 | 820 | case ID_FQDN: |
151168f6 | 821 | case ID_RFC822_ADDR: |
9f9903a3 | 822 | case ID_DER_ASN1_GN_URI: |
c88104aa | 823 | case ID_USER_ID: |
8309798f | 824 | chunk_printable(this->encoded, &proper, '?'); |
a05f3b20 | 825 | snprintf(buf, sizeof(buf), "%.*s", (int)proper.len, proper.ptr); |
b83806d8 | 826 | chunk_free(&proper); |
9f9903a3 | 827 | break; |
151168f6 | 828 | case ID_DER_ASN1_DN: |
8309798f | 829 | dntoa(this->encoded, buf, sizeof(buf)); |
9f9903a3 | 830 | break; |
151168f6 | 831 | case ID_DER_ASN1_GN: |
c04498b6 | 832 | snprintf(buf, sizeof(buf), "(ASN.1 general name)"); |
9f9903a3 | 833 | break; |
151168f6 | 834 | case ID_KEY_ID: |
1ef69b01 MW |
835 | if (chunk_printable(this->encoded, NULL, '?') && |
836 | this->encoded.len != HASH_SIZE_SHA1) | |
a44bb934 | 837 | { /* fully printable, use ascii version */ |
a05f3b20 TB |
838 | snprintf(buf, sizeof(buf), "%.*s", (int)this->encoded.len, |
839 | this->encoded.ptr); | |
a44bb934 MW |
840 | } |
841 | else | |
842 | { /* not printable, hex dump */ | |
843 | snprintf(buf, sizeof(buf), "%#B", &this->encoded); | |
844 | } | |
a44bb934 | 845 | break; |
151168f6 | 846 | default: |
9f9903a3 MW |
847 | snprintf(buf, sizeof(buf), "(unknown ID type: %d)", this->type); |
848 | break; | |
151168f6 | 849 | } |
d25ce370 | 850 | if (spec->minus) |
5dc31719 | 851 | { |
1b40b74d | 852 | return print_in_hook(data, "%-*s", spec->width, buf); |
5dc31719 | 853 | } |
1b40b74d | 854 | return print_in_hook(data, "%*s", spec->width, buf); |
151168f6 | 855 | } |
2fcb2cc6 | 856 | |
f7c32fee | 857 | METHOD(identification_t, clone_, identification_t*, |
2fcb2cc6 | 858 | private_identification_t *this) |
16b9a73c | 859 | { |
2147da40 | 860 | private_identification_t *clone = malloc_thing(private_identification_t); |
7daf5226 | 861 | |
2147da40 | 862 | memcpy(clone, this, sizeof(private_identification_t)); |
418dbd62 MW |
863 | if (this->encoded.len) |
864 | { | |
865 | clone->encoded = chunk_clone(this->encoded); | |
866 | } | |
16b9a73c MW |
867 | return &clone->public; |
868 | } | |
869 | ||
2fcb2cc6 MW |
870 | METHOD(identification_t, destroy, void, |
871 | private_identification_t *this) | |
d45ec1de | 872 | { |
151168f6 MW |
873 | chunk_free(&this->encoded); |
874 | free(this); | |
d45ec1de MW |
875 | } |
876 | ||
a8c09d8c | 877 | /** |
d794bcdb | 878 | * Generic constructor used for the other constructors. |
d45ec1de | 879 | */ |
0c31b9db | 880 | static private_identification_t *identification_create(id_type_t type) |
d45ec1de | 881 | { |
2fcb2cc6 | 882 | private_identification_t *this; |
7daf5226 | 883 | |
2fcb2cc6 MW |
884 | INIT(this, |
885 | .public = { | |
886 | .get_encoding = _get_encoding, | |
887 | .get_type = _get_type, | |
888 | .create_part_enumerator = _create_part_enumerator, | |
f7c32fee | 889 | .clone = _clone_, |
2fcb2cc6 MW |
890 | .destroy = _destroy, |
891 | }, | |
892 | .type = type, | |
893 | ); | |
7daf5226 | 894 | |
0c31b9db MW |
895 | switch (type) |
896 | { | |
897 | case ID_ANY: | |
2fcb2cc6 MW |
898 | this->public.matches = _matches_any; |
899 | this->public.equals = _equals_binary; | |
900 | this->public.contains_wildcards = return_true; | |
0c31b9db MW |
901 | break; |
902 | case ID_FQDN: | |
903 | case ID_RFC822_ADDR: | |
c88104aa | 904 | case ID_USER_ID: |
2fcb2cc6 MW |
905 | this->public.matches = _matches_string; |
906 | this->public.equals = _equals_strcasecmp; | |
907 | this->public.contains_wildcards = _contains_wildcards_memchr; | |
0c31b9db MW |
908 | break; |
909 | case ID_DER_ASN1_DN: | |
2fcb2cc6 MW |
910 | this->public.equals = _equals_dn; |
911 | this->public.matches = _matches_dn; | |
912 | this->public.contains_wildcards = _contains_wildcards_dn; | |
0c31b9db MW |
913 | break; |
914 | default: | |
2fcb2cc6 MW |
915 | this->public.equals = _equals_binary; |
916 | this->public.matches = _matches_binary; | |
917 | this->public.contains_wildcards = return_false; | |
0c31b9db MW |
918 | break; |
919 | } | |
d45ec1de MW |
920 | return this; |
921 | } | |
922 | ||
923 | /* | |
924 | * Described in header. | |
925 | */ | |
a8c09d8c | 926 | identification_t *identification_create_from_string(char *string) |
d45ec1de | 927 | { |
0c31b9db MW |
928 | private_identification_t *this; |
929 | chunk_t encoded; | |
7daf5226 | 930 | |
fec9cb33 | 931 | if (string == NULL) |
151168f6 | 932 | { |
fec9cb33 | 933 | string = "%any"; |
151168f6 | 934 | } |
a8c09d8c | 935 | if (strchr(string, '=') != NULL) |
d45ec1de | 936 | { |
a8c09d8c MW |
937 | /* we interpret this as an ASCII X.501 ID_DER_ASN1_DN. |
938 | * convert from LDAP style or openssl x509 -subject style to ASN.1 DN | |
a8c09d8c | 939 | */ |
0c31b9db MW |
940 | if (atodn(string, &encoded) == SUCCESS) |
941 | { | |
942 | this = identification_create(ID_DER_ASN1_DN); | |
943 | this->encoded = encoded; | |
944 | } | |
945 | else | |
d45ec1de | 946 | { |
0c31b9db | 947 | this = identification_create(ID_KEY_ID); |
78c37de1 | 948 | this->encoded = chunk_from_str(strdup(string)); |
a8c09d8c | 949 | } |
a8c09d8c MW |
950 | return &this->public; |
951 | } | |
952 | else if (strchr(string, '@') == NULL) | |
953 | { | |
456a31e8 TB |
954 | if (streq(string, "") |
955 | || streq(string, "%any") | |
956 | || streq(string, "%any6") | |
353c7b57 AS |
957 | || streq(string, "0.0.0.0") |
958 | || streq(string, "*") | |
959 | || streq(string, "::") | |
960 | || streq(string, "0::0")) | |
a8c09d8c MW |
961 | { |
962 | /* any ID will be accepted */ | |
0c31b9db | 963 | this = identification_create(ID_ANY); |
a8c09d8c MW |
964 | return &this->public; |
965 | } | |
966 | else | |
967 | { | |
a8c09d8c MW |
968 | if (strchr(string, ':') == NULL) |
969 | { | |
a8c09d8c MW |
970 | struct in_addr address; |
971 | chunk_t chunk = {(void*)&address, sizeof(address)}; | |
7daf5226 | 972 | |
0c31b9db MW |
973 | if (inet_pton(AF_INET, string, &address) > 0) |
974 | { /* is IPv4 */ | |
975 | this = identification_create(ID_IPV4_ADDR); | |
976 | this->encoded = chunk_clone(chunk); | |
977 | } | |
978 | else | |
979 | { /* not IPv4, mostly FQDN */ | |
980 | this = identification_create(ID_FQDN); | |
78c37de1 | 981 | this->encoded = chunk_from_str(strdup(string)); |
a8c09d8c | 982 | } |
a44bb934 | 983 | return &this->public; |
a8c09d8c MW |
984 | } |
985 | else | |
986 | { | |
a8c09d8c MW |
987 | struct in6_addr address; |
988 | chunk_t chunk = {(void*)&address, sizeof(address)}; | |
7daf5226 | 989 | |
0c31b9db MW |
990 | if (inet_pton(AF_INET6, string, &address) > 0) |
991 | { /* is IPv6 */ | |
992 | this = identification_create(ID_IPV6_ADDR); | |
993 | this->encoded = chunk_clone(chunk); | |
994 | } | |
995 | else | |
996 | { /* not IPv4/6 fallback to KEY_ID */ | |
997 | this = identification_create(ID_KEY_ID); | |
78c37de1 | 998 | this->encoded = chunk_from_str(strdup(string)); |
a8c09d8c | 999 | } |
a44bb934 | 1000 | return &this->public; |
a8c09d8c MW |
1001 | } |
1002 | } | |
1003 | } | |
1004 | else | |
1005 | { | |
1006 | if (*string == '@') | |
1007 | { | |
cb6c4e04 MW |
1008 | string++; |
1009 | if (*string == '#') | |
d45ec1de | 1010 | { |
0c31b9db | 1011 | this = identification_create(ID_KEY_ID); |
cb6c4e04 MW |
1012 | this->encoded = chunk_from_hex(chunk_from_str(string + 1), NULL); |
1013 | return &this->public; | |
1014 | } | |
1015 | else if (*string == '@') | |
1016 | { | |
1017 | this = identification_create(ID_USER_FQDN); | |
1018 | this->encoded = chunk_clone(chunk_from_str(string + 1)); | |
a44bb934 | 1019 | return &this->public; |
d45ec1de | 1020 | } |
a8c09d8c MW |
1021 | else |
1022 | { | |
0c31b9db | 1023 | this = identification_create(ID_FQDN); |
cb6c4e04 | 1024 | this->encoded = chunk_clone(chunk_from_str(string)); |
a44bb934 | 1025 | return &this->public; |
a8c09d8c | 1026 | } |
d45ec1de | 1027 | } |
a8c09d8c | 1028 | else |
d45ec1de | 1029 | { |
0c31b9db | 1030 | this = identification_create(ID_RFC822_ADDR); |
78c37de1 | 1031 | this->encoded = chunk_from_str(strdup(string)); |
a44bb934 | 1032 | return &this->public; |
d45ec1de MW |
1033 | } |
1034 | } | |
32452870 MW |
1035 | } |
1036 | ||
1037 | /* | |
1038 | * Described in header. | |
1039 | */ | |
1040 | identification_t * identification_create_from_data(chunk_t data) | |
1041 | { | |
1042 | char buf[data.len + 1]; | |
1043 | ||
c88104aa AS |
1044 | if (is_asn1(data)) |
1045 | { | |
1046 | return identification_create_from_encoding(ID_DER_ASN1_DN, data); | |
1047 | } | |
1048 | else | |
1049 | { | |
1050 | /* use string constructor */ | |
1051 | snprintf(buf, sizeof(buf), "%.*s", (int)data.len, data.ptr); | |
1052 | return identification_create_from_string(buf); | |
1053 | } | |
d45ec1de MW |
1054 | } |
1055 | ||
1056 | /* | |
1057 | * Described in header. | |
1058 | */ | |
0c31b9db MW |
1059 | identification_t *identification_create_from_encoding(id_type_t type, |
1060 | chunk_t encoded) | |
d45ec1de | 1061 | { |
0c31b9db | 1062 | private_identification_t *this = identification_create(type); |
7daf5226 | 1063 | |
a8c09d8c MW |
1064 | /* apply encoded chunk */ |
1065 | if (type != ID_ANY) | |
1066 | { | |
1067 | this->encoded = chunk_clone(encoded); | |
1068 | } | |
9151843f | 1069 | return &(this->public); |
d45ec1de | 1070 | } |
eda454a2 | 1071 | |
4b4f8bd7 AS |
1072 | /* |
1073 | * Described in header. | |
1074 | */ | |
1075 | identification_t *identification_create_from_sockaddr(sockaddr_t *sockaddr) | |
1076 | { | |
1077 | switch (sockaddr->sa_family) | |
1078 | { | |
1079 | case AF_INET: | |
1080 | { | |
1081 | struct in_addr *addr = &(((struct sockaddr_in*)sockaddr)->sin_addr); | |
1082 | ||
1083 | return identification_create_from_encoding(ID_IPV4_ADDR, | |
1084 | chunk_create((u_char*)addr, sizeof(struct in_addr))); | |
1085 | } | |
1086 | case AF_INET6: | |
1087 | { | |
1088 | struct in6_addr *addr = &(((struct sockaddr_in6*)sockaddr)->sin6_addr); | |
1089 | ||
1090 | return identification_create_from_encoding(ID_IPV6_ADDR, | |
1091 | chunk_create((u_char*)addr, sizeof(struct in6_addr))); | |
1092 | } | |
1093 | default: | |
1094 | { | |
1095 | private_identification_t *this = identification_create(ID_ANY); | |
1096 | ||
1097 | return &(this->public); | |
1098 | } | |
1099 | } | |
1100 | } |