Line data Source code
1 : /* name.c - Object to access GeneralNames etc.
2 : * Copyright (C) 2002, 2012 g10 Code GmbH
3 : *
4 : * This file is part of KSBA.
5 : *
6 : * KSBA is free software; you can redistribute it and/or modify
7 : * it under the terms of either
8 : *
9 : * - the GNU Lesser General Public License as published by the Free
10 : * Software Foundation; either version 3 of the License, or (at
11 : * your option) any later version.
12 : *
13 : * or
14 : *
15 : * - the GNU General Public License as published by the Free
16 : * Software Foundation; either version 2 of the License, or (at
17 : * your option) any later version.
18 : *
19 : * or both in parallel, as here.
20 : *
21 : * KSBA is distributed in the hope that it will be useful, but WITHOUT
22 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 : * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
24 : * License for more details.
25 : *
26 : * You should have received a copies of the GNU General Public License
27 : * and the GNU Lesser General Public License along with this program;
28 : * if not, see <http://www.gnu.org/licenses/>.
29 : */
30 :
31 : #include <config.h>
32 : #include <stdio.h>
33 : #include <stdlib.h>
34 : #include <string.h>
35 : #include <assert.h>
36 : #include <errno.h>
37 :
38 : #include "util.h"
39 : #include "asn1-func.h"
40 : #include "convert.h"
41 : #include "ber-help.h"
42 :
43 :
44 : struct ksba_name_s {
45 : int ref_count;
46 : int n_names; /* number of names */
47 : char **names; /* array with the parsed names */
48 : };
49 :
50 :
51 : /* Also this is a public function it is not yet usable becuase we
52 : don't have a way to set real information. */
53 : gpg_error_t
54 4 : ksba_name_new (ksba_name_t *r_name)
55 : {
56 4 : *r_name = xtrycalloc (1, sizeof **r_name);
57 4 : if (!*r_name)
58 0 : return gpg_error_from_errno (errno);
59 4 : (*r_name)->ref_count++;
60 :
61 4 : return 0;
62 : }
63 :
64 : void
65 0 : ksba_name_ref (ksba_name_t name)
66 : {
67 0 : if (!name)
68 0 : fprintf (stderr, "BUG: ksba_name_ref for NULL\n");
69 : else
70 0 : ++name->ref_count;
71 0 : }
72 :
73 :
74 : void
75 6 : ksba_name_release (ksba_name_t name)
76 : {
77 : int i;
78 :
79 6 : if (!name)
80 2 : return;
81 4 : if (name->ref_count < 1)
82 : {
83 0 : fprintf (stderr, "BUG: trying to release an already released name\n");
84 0 : return;
85 : }
86 4 : if (--name->ref_count)
87 0 : return;
88 :
89 8 : for (i=0; i < name->n_names; i++)
90 4 : xfree (name->names[i]);
91 4 : xfree (name->names);
92 4 : name->n_names = 0;
93 4 : xfree (name);
94 : }
95 :
96 :
97 : /* This is an internal function to create an ksba_name_t object from an
98 : DER encoded image which must point to an GeneralNames object */
99 : gpg_error_t
100 4 : _ksba_name_new_from_der (ksba_name_t *r_name,
101 : const unsigned char *image, size_t imagelen)
102 : {
103 : gpg_error_t err;
104 : ksba_name_t name;
105 : struct tag_info ti;
106 : const unsigned char *der;
107 : size_t derlen;
108 : int n;
109 : char *p;
110 :
111 4 : if (!r_name || !image)
112 0 : return gpg_error (GPG_ERR_INV_VALUE);
113 :
114 4 : *r_name = NULL;
115 :
116 : /* Count and check for encoding errors - we won't do this again
117 : during the second pass */
118 4 : der = image;
119 4 : derlen = imagelen;
120 4 : n = 0;
121 12 : while (derlen)
122 : {
123 4 : err = _ksba_ber_parse_tl (&der, &derlen, &ti);
124 4 : if (err)
125 0 : return err;
126 4 : if (ti.class != CLASS_CONTEXT)
127 0 : return gpg_error (GPG_ERR_INV_CERT_OBJ); /* we expected a tag */
128 4 : if (ti.ndef)
129 0 : return gpg_error (GPG_ERR_NOT_DER_ENCODED);
130 4 : if (derlen < ti.length)
131 0 : return gpg_error (GPG_ERR_BAD_BER);
132 4 : switch (ti.tag)
133 : {
134 : case 1: /* rfc822Name - this is an imlicit IA5_STRING */
135 : case 4: /* Name */
136 : case 6: /* URI */
137 4 : n++;
138 4 : break;
139 : default:
140 0 : break;
141 : }
142 :
143 : /* advance pointer */
144 4 : der += ti.length;
145 4 : derlen -= ti.length;
146 : }
147 :
148 : /* allocate array and set all slots to NULL for easier error recovery */
149 4 : err = ksba_name_new (&name);
150 4 : if (err)
151 0 : return err;
152 4 : if (!n)
153 0 : return 0; /* empty GeneralNames */
154 4 : name->names = xtrycalloc (n, sizeof *name->names);
155 4 : if (!name->names)
156 : {
157 0 : ksba_name_release (name);
158 0 : return gpg_error (GPG_ERR_ENOMEM);
159 : }
160 4 : name->n_names = n;
161 :
162 : /* start the second pass */
163 4 : der = image;
164 4 : derlen = imagelen;
165 4 : n = 0;
166 12 : while (derlen)
167 : {
168 : char numbuf[21];
169 :
170 4 : err = _ksba_ber_parse_tl (&der, &derlen, &ti);
171 4 : assert (!err);
172 4 : switch (ti.tag)
173 : {
174 : case 1: /* rfc822Name - this is an imlicit IA5_STRING */
175 0 : p = name->names[n] = xtrymalloc (ti.length+3);
176 0 : if (!p)
177 : {
178 0 : ksba_name_release (name);
179 0 : return gpg_error (GPG_ERR_ENOMEM);
180 : }
181 0 : *p++ = '<';
182 0 : memcpy (p, der, ti.length);
183 0 : p += ti.length;
184 0 : *p++ = '>';
185 0 : *p = 0;
186 0 : n++;
187 0 : break;
188 : case 4: /* Name */
189 2 : err = _ksba_derdn_to_str (der, ti.length, &p);
190 2 : if (err)
191 0 : return err; /* FIXME: we need to release some of the memory */
192 2 : name->names[n++] = p;
193 2 : break;
194 : case 6: /* URI */
195 2 : sprintf (numbuf, "%u:", (unsigned int)ti.length);
196 2 : p = name->names[n] = xtrymalloc (1+5+strlen (numbuf)
197 : + ti.length +1+1);
198 2 : if (!p)
199 : {
200 0 : ksba_name_release (name);
201 0 : return gpg_error (GPG_ERR_ENOMEM);
202 : }
203 2 : p = stpcpy (p, "(3:uri");
204 2 : p = stpcpy (p, numbuf);
205 2 : memcpy (p, der, ti.length);
206 2 : p += ti.length;
207 2 : *p++ = ')';
208 2 : *p = 0; /* extra safeguard null */
209 2 : n++;
210 2 : break;
211 : default:
212 0 : break;
213 : }
214 :
215 : /* advance pointer */
216 4 : der += ti.length;
217 4 : derlen -= ti.length;
218 : }
219 4 : *r_name = name;
220 4 : return 0;
221 : }
222 :
223 :
224 : /* By iterating IDX up starting with 0, this function returns the all
225 : General Names stored in NAME. The format of the returned name is
226 : either a RFC-2253 formated one which can be detected by checking
227 : whether the first character is letter or a digit. RFC 2822 conform
228 : email addresses are returned enclosed in angle brackets, the
229 : opening angle bracket should be used to detect this. Other formats
230 : are returned as an S-Expression in canonical format, so a opening
231 : parenthesis may be used to detect this encoding, in this case the
232 : name may include binary null characters, so strlen might return a
233 : length shorter than actually used, the real length is implictly
234 : given by the structure of the S-Exp, an extra null is appended for
235 : safety reasons. One common format return is probably an Universal
236 : Resource Identifier which has the S-expression: "(uri <urivalue>)".
237 :
238 : The return string has the same lifetime as NAME. */
239 : const char *
240 12 : ksba_name_enum (ksba_name_t name, int idx)
241 : {
242 12 : if (!name || idx < 0)
243 0 : return NULL;
244 12 : if (idx >= name->n_names)
245 4 : return NULL; /* end of list */
246 :
247 8 : return name->names[idx];
248 : }
249 :
250 : /* Convenience function to return names representing an URI. Caller
251 : must free the return value. Note that this function should not be
252 : used for enumeration */
253 : char *
254 4 : ksba_name_get_uri (ksba_name_t name, int idx)
255 : {
256 4 : const char *s = ksba_name_enum (name, idx);
257 : int n;
258 : char *buf;
259 :
260 4 : if (!s || strncmp (s, "(3:uri", 6))
261 2 : return NULL; /* we do only return URIs */
262 2 : s += 6;
263 6 : for (n=0; *s && *s != ':' && digitp (s); s++)
264 4 : n = n*10 + atoi_1 (s);
265 2 : if (!n || *s != ':')
266 0 : return NULL; /* oops */
267 2 : s++;
268 2 : buf = xtrymalloc (n+1);
269 2 : if (buf)
270 : {
271 2 : memcpy (buf, s, n);
272 2 : buf[n] = 0;
273 : }
274 2 : return buf;
275 : }
|