2 * Copyright (C) 2009 Tobias Brunner
3 * Copyright (C) 2005-2009 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
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>.
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
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
26 #include "identification.h"
29 #include <asn1/asn1.h>
31 ENUM_BEGIN(id_match_names
, ID_MATCH_NONE
, ID_MATCH_MAX_WILDCARDS
,
34 "MATCH_MAX_WILDCARDS");
35 ENUM_NEXT(id_match_names
, ID_MATCH_PERFECT
, ID_MATCH_PERFECT
, ID_MATCH_MAX_WILDCARDS
,
37 ENUM_END(id_match_names
, ID_MATCH_PERFECT
);
39 ENUM_BEGIN(id_type_names
, ID_ANY
, ID_KEY_ID
,
44 "ID_IPV4_ADDR_SUBNET",
46 "ID_IPV6_ADDR_SUBNET",
52 ENUM_NEXT(id_type_names
, ID_DER_ASN1_GN_URI
, ID_CERT_DER_SHA1
, ID_KEY_ID
,
54 "ID_PUBKEY_INFO_SHA1",
57 ENUM_END(id_type_names
, ID_CERT_DER_SHA1
);
60 * coding of X.501 distinguished name
68 static const x501rdn_t x501rdns
[] = {
69 {"ND", OID_NAME_DISTINGUISHER
, ASN1_PRINTABLESTRING
},
70 {"UID", OID_PILOT_USERID
, ASN1_PRINTABLESTRING
},
71 {"DC", OID_PILOT_DOMAIN_COMPONENT
, ASN1_PRINTABLESTRING
},
72 {"CN", OID_COMMON_NAME
, ASN1_PRINTABLESTRING
},
73 {"S", OID_SURNAME
, ASN1_PRINTABLESTRING
},
74 {"SN", OID_SERIAL_NUMBER
, ASN1_PRINTABLESTRING
},
75 {"serialNumber", OID_SERIAL_NUMBER
, ASN1_PRINTABLESTRING
},
76 {"C", OID_COUNTRY
, ASN1_PRINTABLESTRING
},
77 {"L", OID_LOCALITY
, ASN1_PRINTABLESTRING
},
78 {"ST", OID_STATE_OR_PROVINCE
, ASN1_PRINTABLESTRING
},
79 {"O", OID_ORGANIZATION
, ASN1_PRINTABLESTRING
},
80 {"OU", OID_ORGANIZATION_UNIT
, ASN1_PRINTABLESTRING
},
81 {"T", OID_TITLE
, ASN1_PRINTABLESTRING
},
82 {"D", OID_DESCRIPTION
, ASN1_PRINTABLESTRING
},
83 {"N", OID_NAME
, ASN1_PRINTABLESTRING
},
84 {"G", OID_GIVEN_NAME
, ASN1_PRINTABLESTRING
},
85 {"I", OID_INITIALS
, ASN1_PRINTABLESTRING
},
86 {"ID", OID_UNIQUE_IDENTIFIER
, ASN1_PRINTABLESTRING
},
87 {"EN", OID_EMPLOYEE_NUMBER
, ASN1_PRINTABLESTRING
},
88 {"employeeNumber", OID_EMPLOYEE_NUMBER
, ASN1_PRINTABLESTRING
},
89 {"E", OID_EMAIL_ADDRESS
, ASN1_IA5STRING
},
90 {"Email", OID_EMAIL_ADDRESS
, ASN1_IA5STRING
},
91 {"emailAddress", OID_EMAIL_ADDRESS
, ASN1_IA5STRING
},
92 {"UN", OID_UNSTRUCTURED_NAME
, ASN1_IA5STRING
},
93 {"unstructuredName",OID_UNSTRUCTURED_NAME
, ASN1_IA5STRING
},
94 {"TCGID", OID_TCGID
, ASN1_PRINTABLESTRING
}
98 * maximum number of RDNs in atodn()
103 typedef struct private_identification_t private_identification_t
;
106 * Private data of an identification_t object.
108 struct private_identification_t
{
112 identification_t
public;
115 * Encoded representation of this ID.
126 * Enumerator over RDNs
129 /* implements enumerator interface */
131 /* RDNs left to parse */
136 * Implementation of rdn_enumerator_t.enumerate
138 static bool rdn_enumerate(rdn_enumerator_t
*this, chunk_t
*oid
,
139 u_char
*type
, chunk_t
*data
)
143 /* a RDN is a SET of attribute-values, each is a SEQUENCE ... */
144 if (asn1_unwrap(&this->left
, &rdn
) == ASN1_SET
&&
145 asn1_unwrap(&rdn
, &rdn
) == ASN1_SEQUENCE
)
148 if (asn1_unwrap(&rdn
, oid
) == ASN1_OID
)
150 /* and a specific string type */
151 *type
= asn1_unwrap(&rdn
, data
);
152 if (*type
!= ASN1_INVALID
)
162 * Create an enumerator over all RDNs (oid, string type, data) of a DN
164 static enumerator_t
* create_rdn_enumerator(chunk_t dn
)
166 rdn_enumerator_t
*e
= malloc_thing(rdn_enumerator_t
);
168 e
->public.enumerate
= (void*)rdn_enumerate
;
169 e
->public.destroy
= (void*)free
;
171 /* a DN is a sequence of RDNs */
172 if (asn1_unwrap(&dn
, &e
->left
) == ASN1_SEQUENCE
)
176 return enumerator_create_empty();
180 * Part enumerator over RDNs
183 /* implements enumerator interface */
185 /* inner RDN enumerator */
187 } rdn_part_enumerator_t
;
190 * Implementation of rdn_part_enumerator_t.enumerate().
192 static bool rdn_part_enumerate(rdn_part_enumerator_t
*this,
193 id_part_t
*type
, chunk_t
*data
)
195 int i
, known_oid
, strtype
;
196 chunk_t oid
, inner_data
;
197 static const struct {
201 {OID_COMMON_NAME
, ID_PART_RDN_CN
},
202 {OID_SURNAME
, ID_PART_RDN_S
},
203 {OID_SERIAL_NUMBER
, ID_PART_RDN_SN
},
204 {OID_COUNTRY
, ID_PART_RDN_C
},
205 {OID_LOCALITY
, ID_PART_RDN_L
},
206 {OID_STATE_OR_PROVINCE
, ID_PART_RDN_ST
},
207 {OID_ORGANIZATION
, ID_PART_RDN_O
},
208 {OID_ORGANIZATION_UNIT
, ID_PART_RDN_OU
},
209 {OID_TITLE
, ID_PART_RDN_T
},
210 {OID_DESCRIPTION
, ID_PART_RDN_D
},
211 {OID_NAME
, ID_PART_RDN_N
},
212 {OID_GIVEN_NAME
, ID_PART_RDN_G
},
213 {OID_INITIALS
, ID_PART_RDN_I
},
214 {OID_UNIQUE_IDENTIFIER
, ID_PART_RDN_ID
},
215 {OID_EMAIL_ADDRESS
, ID_PART_RDN_E
},
216 {OID_EMPLOYEE_NUMBER
, ID_PART_RDN_EN
},
219 while (this->inner
->enumerate(this->inner
, &oid
, &strtype
, &inner_data
))
221 known_oid
= asn1_known_oid(oid
);
222 for (i
= 0; i
< countof(oid2part
); i
++)
224 if (oid2part
[i
].oid
== known_oid
)
226 *type
= oid2part
[i
].type
;
236 * Implementation of rdn_part_enumerator_t.destroy().
238 static void rdn_part_enumerator_destroy(rdn_part_enumerator_t
*this)
240 this->inner
->destroy(this->inner
);
245 * Implementation of identification_t.create_part_enumerator
247 static enumerator_t
* create_part_enumerator(private_identification_t
*this)
253 rdn_part_enumerator_t
*e
= malloc_thing(rdn_part_enumerator_t
);
255 e
->inner
= create_rdn_enumerator(this->encoded
);
256 e
->public.enumerate
= (void*)rdn_part_enumerate
;
257 e
->public.destroy
= (void*)rdn_part_enumerator_destroy
;
266 return enumerator_create_empty();
270 static private_identification_t
*identification_create(void);
273 * updates a chunk (!????)
274 * TODO: We should reconsider this stuff, its not really clear
276 static void update_chunk(chunk_t
*ch
, int n
)
278 n
= (n
> -1 && n
< (int)ch
->len
)? n
: (int)ch
->len
-1;
279 ch
->ptr
+= n
; ch
->len
-= n
;
283 * Remove any malicious characters from a chunk. We are very restrictive, but
284 * whe use these strings only to present it to the user.
286 static bool sanitize_chunk(chunk_t chunk
, chunk_t
*clone
)
289 bool all_printable
= TRUE
;
291 *clone
= chunk_clone(chunk
);
293 for (pos
= clone
->ptr
; pos
< (char*)(clone
->ptr
+ clone
->len
); pos
++)
298 all_printable
= FALSE
;
301 return all_printable
;
305 * Pointer is set to the first RDN in a DN
307 static bool init_rdn(chunk_t dn
, chunk_t
*rdn
, chunk_t
*attribute
, bool *next
)
310 *attribute
= chunk_empty
;
312 /* a DN is a SEQUENCE OF RDNs */
313 if (*dn
.ptr
!= ASN1_SEQUENCE
)
315 /* DN is not a SEQUENCE */
319 rdn
->len
= asn1_length(&dn
);
321 if (rdn
->len
== ASN1_INVALID_LENGTH
)
323 /* Invalid RDN length */
329 /* are there any RDNs ? */
330 *next
= rdn
->len
> 0;
336 * Fetches the next RDN in a DN
338 static bool get_next_rdn(chunk_t
*rdn
, chunk_t
* attribute
, chunk_t
*oid
,
339 chunk_t
*value
, asn1_t
*type
, bool *next
)
343 /* initialize return values */
345 *value
= chunk_empty
;
347 /* if all attributes have been parsed, get next rdn */
348 if (attribute
->len
<= 0)
350 /* an RDN is a SET OF attributeTypeAndValue */
351 if (*rdn
->ptr
!= ASN1_SET
)
353 /* RDN is not a SET */
356 attribute
->len
= asn1_length(rdn
);
357 if (attribute
->len
== ASN1_INVALID_LENGTH
)
359 /* Invalid attribute length */
362 attribute
->ptr
= rdn
->ptr
;
363 /* advance to start of next RDN */
364 rdn
->ptr
+= attribute
->len
;
365 rdn
->len
-= attribute
->len
;
368 /* an attributeTypeAndValue is a SEQUENCE */
369 if (*attribute
->ptr
!= ASN1_SEQUENCE
)
371 /* attributeTypeAndValue is not a SEQUENCE */
375 /* extract the attribute body */
376 body
.len
= asn1_length(attribute
);
378 if (body
.len
== ASN1_INVALID_LENGTH
)
380 /* Invalid attribute body length */
384 body
.ptr
= attribute
->ptr
;
386 /* advance to start of next attribute */
387 attribute
->ptr
+= body
.len
;
388 attribute
->len
-= body
.len
;
390 /* attribute type is an OID */
391 if (*body
.ptr
!= ASN1_OID
)
393 /* attributeType is not an OID */
397 oid
->len
= asn1_length(&body
);
399 if (oid
->len
== ASN1_INVALID_LENGTH
)
401 /* Invalid attribute OID length */
406 /* advance to the attribute value */
407 body
.ptr
+= oid
->len
;
408 body
.len
-= oid
->len
;
410 /* extract string type */
413 /* extract string value */
414 value
->len
= asn1_length(&body
);
416 if (value
->len
== ASN1_INVALID_LENGTH
)
418 /* Invalid attribute string length */
421 value
->ptr
= body
.ptr
;
423 /* are there any RDNs left? */
424 *next
= rdn
->len
> 0 || attribute
->len
> 0;
429 * Parses an ASN.1 distinguished name int its OID/value pairs
431 static bool dntoa(chunk_t dn
, chunk_t
*str
)
433 chunk_t rdn
, oid
, attribute
, value
, proper
;
439 if (!init_rdn(dn
, &rdn
, &attribute
, &next
))
446 if (!get_next_rdn(&rdn
, &attribute
, &oid
, &value
, &type
, &next
))
452 { /* first OID/value pair */
456 { /* separate OID/value pair by a comma */
457 update_chunk(str
, snprintf(str
->ptr
,str
->len
,", "));
461 oid_code
= asn1_known_oid(oid
);
462 if (oid_code
== OID_UNKNOWN
)
464 update_chunk(str
, snprintf(str
->ptr
,str
->len
,"0x#B", &oid
));
468 update_chunk(str
, snprintf(str
->ptr
,str
->len
,"%s", oid_names
[oid_code
].name
));
471 sanitize_chunk(value
, &proper
);
472 update_chunk(str
, snprintf(str
->ptr
,str
->len
,"=%.*s", (int)proper
.len
, proper
.ptr
));
479 * compare two distinguished names by
480 * comparing the individual RDNs
482 static bool same_dn(chunk_t a
, chunk_t b
)
484 chunk_t rdn_a
, rdn_b
, attribute_a
, attribute_b
;
485 chunk_t oid_a
, oid_b
, value_a
, value_b
;
486 asn1_t type_a
, type_b
;
489 /* same lengths for the DNs */
494 /* try a binary comparison first */
495 if (memeq(a
.ptr
, b
.ptr
, b
.len
))
499 /* initialize DN parsing */
500 if (!init_rdn(a
, &rdn_a
, &attribute_a
, &next_a
) ||
501 !init_rdn(b
, &rdn_b
, &attribute_b
, &next_b
))
506 /* fetch next RDN pair */
507 while (next_a
&& next_b
)
509 /* parse next RDNs and check for errors */
510 if (!get_next_rdn(&rdn_a
, &attribute_a
, &oid_a
, &value_a
, &type_a
, &next_a
) ||
511 !get_next_rdn(&rdn_b
, &attribute_b
, &oid_b
, &value_b
, &type_b
, &next_b
))
516 /* OIDs must agree */
517 if (oid_a
.len
!= oid_b
.len
|| !memeq(oid_a
.ptr
, oid_b
.ptr
, oid_b
.len
))
522 /* same lengths for values */
523 if (value_a
.len
!= value_b
.len
)
528 /* printableStrings and email RDNs require uppercase comparison */
529 if (type_a
== type_b
&& (type_a
== ASN1_PRINTABLESTRING
||
530 (type_a
== ASN1_IA5STRING
&& asn1_known_oid(oid_a
) == OID_PKCS9_EMAIL
)))
532 if (strncasecmp(value_a
.ptr
, value_b
.ptr
, value_b
.len
) != 0)
539 if (!strneq(value_a
.ptr
, value_b
.ptr
, value_b
.len
))
545 /* both DNs must have same number of RDNs */
546 if (next_a
|| next_b
)
550 /* the two DNs are equal! */
556 * compare two distinguished names by comparing the individual RDNs.
557 * A single'*' character designates a wildcard RDN in DN b.
558 * TODO: Add support for different RDN order in DN !!
560 bool match_dn(chunk_t a
, chunk_t b
, int *wildcards
)
562 chunk_t rdn_a
, rdn_b
, attribute_a
, attribute_b
;
563 chunk_t oid_a
, oid_b
, value_a
, value_b
;
564 asn1_t type_a
, type_b
;
567 /* initialize wildcard counter */
570 /* initialize DN parsing */
571 if (!init_rdn(a
, &rdn_a
, &attribute_a
, &next_a
) ||
572 !init_rdn(b
, &rdn_b
, &attribute_b
, &next_b
))
577 /* fetch next RDN pair */
578 while (next_a
&& next_b
)
580 /* parse next RDNs and check for errors */
581 if (!get_next_rdn(&rdn_a
, &attribute_a
, &oid_a
, &value_a
, &type_a
, &next_a
) ||
582 !get_next_rdn(&rdn_b
, &attribute_b
, &oid_b
, &value_b
, &type_b
, &next_b
))
586 /* OIDs must agree */
587 if (oid_a
.len
!= oid_b
.len
|| memcmp(oid_a
.ptr
, oid_b
.ptr
, oid_b
.len
) != 0)
592 /* does rdn_b contain a wildcard? */
593 if (value_b
.len
== 1 && *value_b
.ptr
== '*')
598 /* same lengths for values */
599 if (value_a
.len
!= value_b
.len
)
604 /* printableStrings and email RDNs require uppercase comparison */
605 if (type_a
== type_b
&& (type_a
== ASN1_PRINTABLESTRING
||
606 (type_a
== ASN1_IA5STRING
&& asn1_known_oid(oid_a
) == OID_PKCS9_EMAIL
)))
608 if (strncasecmp(value_a
.ptr
, value_b
.ptr
, value_b
.len
) != 0)
615 if (!strneq(value_a
.ptr
, value_b
.ptr
, value_b
.len
))
621 /* both DNs must have same number of RDNs */
622 if (next_a
|| next_b
)
626 /* the two DNs match! */
627 *wildcards
= min(*wildcards
, ID_MATCH_ONE_WILDCARD
- ID_MATCH_MAX_WILDCARDS
);
632 * Converts an LDAP-style human-readable ASCII-encoded
633 * ASN.1 distinguished name into binary DER-encoded format
635 static status_t
atodn(char *src
, chunk_t
*dn
)
637 /* finite state machine for atodn */
646 chunk_t oid
= chunk_empty
;
647 chunk_t name
= chunk_empty
;
648 chunk_t rdns
[RDN_MAX
];
654 state_t state
= SEARCH_OID
;
655 status_t status
= SUCCESS
;
662 if (*src
!= ' ' && *src
!= '/' && *src
!= ',')
670 if (*src
!= ' ' && *src
!= '=')
678 for (i
= 0; i
< countof(x501rdns
); i
++)
680 if (strlen(x501rdns
[i
].name
) == oid
.len
&&
681 strncasecmp(x501rdns
[i
].name
, oid
.ptr
, oid
.len
) == 0)
689 status
= NOT_SUPPORTED
;
693 /* reset oid and change state */
699 if (*src
!= ' ' && *src
!= '=')
708 if (*src
!= ',' && *src
!= '/' && *src
!= '\0')
718 name
.len
-= whitespace
;
719 rdn_type
= (x501rdns
[i
].type
== ASN1_PRINTABLESTRING
720 && !asn1_is_printablestring(name
))
721 ? ASN1_T61STRING
: x501rdns
[i
].type
;
723 if (rdn_count
< RDN_MAX
)
727 rdn_oid
= asn1_build_known_oid(x501rdns
[i
].oid
);
731 asn1_wrap(ASN1_SET
, "m",
732 asn1_wrap(ASN1_SEQUENCE
, "mm",
734 asn1_wrap(rdn_type
, "c", name
)
737 dn_len
+= rdns
[rdn_count
++].len
;
741 status
= INVALID_ARG
;
748 /* reset name and change state */
756 } while (*src
++ != '\0');
758 /* build the distinguished name sequence */
761 u_char
*pos
= asn1_build_object(dn
, ASN1_SEQUENCE
, dn_len
);
763 for (i
= 0; i
< rdn_count
; i
++)
765 memcpy(pos
, rdns
[i
].ptr
, rdns
[i
].len
);
771 if (status
!= SUCCESS
)
780 * Implementation of identification_t.get_encoding.
782 static chunk_t
get_encoding(private_identification_t
*this)
784 return this->encoded
;
788 * Implementation of identification_t.get_type.
790 static id_type_t
get_type(private_identification_t
*this)
796 * Implementation of identification_t.contains_wildcards fro ID_DER_ASN1_DN.
798 static bool contains_wildcards_dn(private_identification_t
*this)
800 chunk_t rdn
, attribute
;
805 if (!init_rdn(this->encoded
, &rdn
, &attribute
, &next
))
812 /* parse next RDN and check for errors */
813 if (!get_next_rdn(&rdn
, &attribute
, &oid
, &value
, &type
, &next
))
817 /* check if RDN is a wildcard */
818 if (value
.len
== 1 && *value
.ptr
== '*')
827 * Implementation of identification_t.contains_wildcards.
829 static bool contains_wildcards(private_identification_t
*this)
837 return memchr(this->encoded
.ptr
, '*', this->encoded
.len
) != NULL
;
839 return contains_wildcards_dn(this);
846 * Default implementation of identification_t.equals.
847 * compares encoded chunk for equality.
849 static bool equals_binary(private_identification_t
*this, private_identification_t
*other
)
851 if (this->type
== other
->type
)
853 if (this->type
== ID_ANY
)
857 return chunk_equals(this->encoded
, other
->encoded
);
863 * Special implementation of identification_t.equals for ID_DER_ASN1_DN.
865 static bool equals_dn(private_identification_t
*this,
866 private_identification_t
*other
)
868 return same_dn(this->encoded
, other
->encoded
);
872 * Special implementation of identification_t.equals for RFC822 and FQDN.
874 static bool equals_strcasecmp(private_identification_t
*this,
875 private_identification_t
*other
)
877 /* we do some extra sanity checks to check for invalid IDs with a
878 * terminating null in it. */
879 if (this->encoded
.len
== other
->encoded
.len
&&
880 memchr(this->encoded
.ptr
, 0, this->encoded
.len
) == NULL
&&
881 memchr(other
->encoded
.ptr
, 0, other
->encoded
.len
) == NULL
&&
882 strncasecmp(this->encoded
.ptr
, other
->encoded
.ptr
, this->encoded
.len
) == 0)
890 * Default implementation of identification_t.matches.
892 static id_match_t
matches_binary(private_identification_t
*this,
893 private_identification_t
*other
)
895 if (other
->type
== ID_ANY
)
899 if (this->type
== other
->type
&&
900 chunk_equals(this->encoded
, other
->encoded
))
902 return ID_MATCH_PERFECT
;
904 return ID_MATCH_NONE
;
908 * Special implementation of identification_t.matches for ID_RFC822_ADDR/ID_FQDN.
909 * Checks for a wildcard in other-string, and compares it against this-string.
911 static id_match_t
matches_string(private_identification_t
*this,
912 private_identification_t
*other
)
914 u_int len
= other
->encoded
.len
;
916 if (other
->type
== ID_ANY
)
920 if (this->type
!= other
->type
)
922 return ID_MATCH_NONE
;
924 /* try a equals check first */
925 if (equals_strcasecmp(this, other
))
927 return ID_MATCH_PERFECT
;
929 if (len
== 0 || this->encoded
.len
< len
)
931 return ID_MATCH_NONE
;
934 /* check for single wildcard at the head of the string */
935 if (*other
->encoded
.ptr
== '*')
937 /* single asterisk matches any string */
939 { /* not better than ID_ANY */
942 if (strncasecmp(this->encoded
.ptr
+ this->encoded
.len
- len
,
943 other
->encoded
.ptr
+ 1, len
) == 0)
945 return ID_MATCH_ONE_WILDCARD
;
948 return ID_MATCH_NONE
;
952 * Special implementation of identification_t.matches for ID_ANY.
953 * ANY matches only another ANY, but nothing other
955 static id_match_t
matches_any(private_identification_t
*this,
956 private_identification_t
*other
)
958 if (other
->type
== ID_ANY
)
962 return ID_MATCH_NONE
;
966 * Special implementation of identification_t.matches for ID_DER_ASN1_DN
968 static id_match_t
matches_dn(private_identification_t
*this,
969 private_identification_t
*other
)
973 if (other
->type
== ID_ANY
)
978 if (this->type
== other
->type
)
980 if (match_dn(this->encoded
, other
->encoded
, &wc
))
982 return ID_MATCH_PERFECT
- wc
;
985 return ID_MATCH_NONE
;
989 * Described in header.
991 int identification_printf_hook(char *dst
, size_t len
, printf_hook_spec_t
*spec
,
992 const void *const *args
)
994 private_identification_t
*this = *((private_identification_t
**)(args
[0]));
996 chunk_t proper
, buf_chunk
= chunk_from_buf(buf
);
1000 return print_in_hook(dst
, len
, "%*s", spec
->width
, "(null)");
1006 snprintf(buf
, sizeof(buf
), "%%any");
1009 if (this->encoded
.len
< sizeof(struct in_addr
) ||
1010 inet_ntop(AF_INET
, this->encoded
.ptr
, buf
, sizeof(buf
)) == NULL
)
1012 snprintf(buf
, sizeof(buf
), "(invalid ID_IPV4_ADDR)");
1016 if (this->encoded
.len
< sizeof(struct in6_addr
) ||
1017 inet_ntop(AF_INET6
, this->encoded
.ptr
, buf
, INET6_ADDRSTRLEN
) == NULL
)
1019 snprintf(buf
, sizeof(buf
), "(invalid ID_IPV6_ADDR)");
1023 case ID_RFC822_ADDR
:
1024 case ID_DER_ASN1_GN_URI
:
1025 case ID_IETF_ATTR_STRING
:
1026 sanitize_chunk(this->encoded
, &proper
);
1027 snprintf(buf
, sizeof(buf
), "%.*s", proper
.len
, proper
.ptr
);
1028 chunk_free(&proper
);
1030 case ID_DER_ASN1_DN
:
1031 if (!dntoa(this->encoded
, &buf_chunk
))
1033 snprintf(buf
, sizeof(buf
), "(invalid ID_DER_ASN1_DN)");
1036 case ID_DER_ASN1_GN
:
1037 snprintf(buf
, sizeof(buf
), "(ASN.1 general Name");
1040 if (sanitize_chunk(this->encoded
, &proper
))
1041 { /* fully printable, use ascii version */
1042 snprintf(buf
, sizeof(buf
), "%.*s", proper
.len
, proper
.ptr
);
1045 { /* not printable, hex dump */
1046 snprintf(buf
, sizeof(buf
), "%#B", &this->encoded
);
1048 chunk_free(&proper
);
1050 case ID_PUBKEY_INFO_SHA1
:
1051 case ID_PUBKEY_SHA1
:
1052 case ID_CERT_DER_SHA1
:
1053 snprintf(buf
, sizeof(buf
), "%#B", &this->encoded
);
1056 snprintf(buf
, sizeof(buf
), "(unknown ID type: %d)", this->type
);
1061 return print_in_hook(dst
, len
, "%-*s", spec
->width
, buf
);
1063 return print_in_hook(dst
, len
, "%*s", spec
->width
, buf
);
1066 * Implementation of identification_t.clone.
1068 static identification_t
*clone_(private_identification_t
*this)
1070 private_identification_t
*clone
= identification_create();
1072 clone
->type
= this->type
;
1073 if (this->encoded
.len
)
1075 clone
->encoded
= chunk_clone(this->encoded
);
1077 clone
->public.equals
= this->public.equals
;
1078 clone
->public.matches
= this->public.matches
;
1080 return &clone
->public;
1084 * Implementation of identification_t.destroy.
1086 static void destroy(private_identification_t
*this)
1088 chunk_free(&this->encoded
);
1093 * Generic constructor used for the other constructors.
1095 static private_identification_t
*identification_create(void)
1097 private_identification_t
*this = malloc_thing(private_identification_t
);
1099 this->public.get_encoding
= (chunk_t (*) (identification_t
*))get_encoding
;
1100 this->public.get_type
= (id_type_t (*) (identification_t
*))get_type
;
1101 this->public.contains_wildcards
= (bool (*) (identification_t
*this))contains_wildcards
;
1102 this->public.create_part_enumerator
= (enumerator_t
*(*)(identification_t
*))create_part_enumerator
;
1103 this->public.clone
= (identification_t
* (*) (identification_t
*))clone_
;
1104 this->public.destroy
= (void (*) (identification_t
*))destroy
;
1105 /* we use these as defaults, the may be overloaded for special ID types */
1106 this->public.equals
= (bool (*) (identification_t
*,identification_t
*))equals_binary
;
1107 this->public.matches
= (id_match_t (*) (identification_t
*,identification_t
*))matches_binary
;
1109 this->encoded
= chunk_empty
;
1115 * Described in header.
1117 identification_t
*identification_create_from_string(char *string
)
1119 private_identification_t
*this = identification_create();
1125 if (strchr(string
, '=') != NULL
)
1127 /* we interpret this as an ASCII X.501 ID_DER_ASN1_DN.
1128 * convert from LDAP style or openssl x509 -subject style to ASN.1 DN
1130 if (atodn(string
, &this->encoded
) != SUCCESS
)
1132 this->type
= ID_KEY_ID
;
1133 this->encoded
= chunk_clone(chunk_create(string
, strlen(string
)));
1134 return &this->public;
1136 this->type
= ID_DER_ASN1_DN
;
1137 this->public.equals
= (bool (*) (identification_t
*,identification_t
*))equals_dn
;
1138 this->public.matches
= (id_match_t (*) (identification_t
*,identification_t
*))matches_dn
;
1139 return &this->public;
1141 else if (strchr(string
, '@') == NULL
)
1143 if (streq(string
, "%any")
1144 || streq(string
, "%any6")
1145 || streq(string
, "0.0.0.0")
1146 || streq(string
, "*")
1147 || streq(string
, "::")
1148 || streq(string
, "0::0"))
1150 /* any ID will be accepted */
1151 this->type
= ID_ANY
;
1152 this->public.matches
= (id_match_t (*)
1153 (identification_t
*,identification_t
*))matches_any
;
1154 return &this->public;
1158 if (strchr(string
, ':') == NULL
)
1161 struct in_addr address
;
1162 chunk_t chunk
= {(void*)&address
, sizeof(address
)};
1164 if (inet_pton(AF_INET
, string
, &address
) <= 0)
1166 /* not IPv4, mostly FQDN */
1167 this->type
= ID_FQDN
;
1168 this->encoded
.ptr
= strdup(string
);
1169 this->encoded
.len
= strlen(string
);
1170 this->public.matches
= (id_match_t (*)
1171 (identification_t
*,identification_t
*))matches_string
;
1172 this->public.equals
= (bool (*)
1173 (identification_t
*,identification_t
*))equals_strcasecmp
;
1174 return &this->public;
1176 this->encoded
= chunk_clone(chunk
);
1177 this->type
= ID_IPV4_ADDR
;
1178 return &this->public;
1183 struct in6_addr address
;
1184 chunk_t chunk
= {(void*)&address
, sizeof(address
)};
1186 if (inet_pton(AF_INET6
, string
, &address
) <= 0)
1188 this->type
= ID_KEY_ID
;
1189 this->encoded
= chunk_clone(chunk_create(string
,
1191 return &this->public;
1193 this->encoded
= chunk_clone(chunk
);
1194 this->type
= ID_IPV6_ADDR
;
1195 return &this->public;
1203 if (*(string
+ 1) == '#')
1206 this->type
= ID_KEY_ID
;
1207 this->encoded
= chunk_from_hex(
1208 chunk_create(string
, strlen(string
)), NULL
);
1209 return &this->public;
1213 this->type
= ID_FQDN
;
1214 this->encoded
.ptr
= strdup(string
+ 1);
1215 this->encoded
.len
= strlen(string
+ 1);
1216 this->public.matches
= (id_match_t (*)
1217 (identification_t
*,identification_t
*))matches_string
;
1218 this->public.equals
= (bool (*)
1219 (identification_t
*,identification_t
*))equals_strcasecmp
;
1220 return &this->public;
1225 this->type
= ID_RFC822_ADDR
;
1226 this->encoded
.ptr
= strdup(string
);
1227 this->encoded
.len
= strlen(string
);
1228 this->public.matches
= (id_match_t (*)
1229 (identification_t
*,identification_t
*))matches_string
;
1230 this->public.equals
= (bool (*)
1231 (identification_t
*,identification_t
*))equals_strcasecmp
;
1232 return &this->public;
1238 * Described in header.
1240 identification_t
*identification_create_from_encoding(id_type_t type
, chunk_t encoded
)
1242 private_identification_t
*this = identification_create();
1248 this->public.matches
= (id_match_t (*)
1249 (identification_t
*,identification_t
*))matches_any
;
1252 case ID_RFC822_ADDR
:
1253 this->public.matches
= (id_match_t (*)
1254 (identification_t
*,identification_t
*))matches_string
;
1255 this->public.equals
= (bool (*)
1256 (identification_t
*,identification_t
*))equals_strcasecmp
;
1258 case ID_DER_ASN1_DN
:
1259 this->public.equals
= (bool (*)
1260 (identification_t
*,identification_t
*))equals_dn
;
1261 this->public.matches
= (id_match_t (*)
1262 (identification_t
*,identification_t
*))matches_dn
;
1266 case ID_DER_ASN1_GN
:
1268 case ID_DER_ASN1_GN_URI
:
1269 case ID_PUBKEY_INFO_SHA1
:
1270 case ID_PUBKEY_SHA1
:
1271 case ID_CERT_DER_SHA1
:
1272 case ID_IETF_ATTR_STRING
:
1277 /* apply encoded chunk */
1280 this->encoded
= chunk_clone(encoded
);
1282 return &(this->public);