Branch data Line data Source code
1 : : /*
2 : : * gnome-keyring
3 : : *
4 : : * Copyright (C) 2011 Collabora Ltd.
5 : : *
6 : : * This program is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU Lesser General Public License as
8 : : * published by the Free Software Foundation; either version 2.1 of
9 : : * the License, or (at your option) any later version.
10 : : *
11 : : * This program is distributed in the hope that it will be useful, but
12 : : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Lesser General Public
17 : : * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : : *
19 : : * Author: Stef Walter <stefw@collabora.co.uk>
20 : : */
21 : : #include "config.h"
22 : :
23 : : #include "gcr-certificate-extensions.h"
24 : :
25 : : #include "gcr/gcr-oids.h"
26 : :
27 : : #include "egg/egg-asn1x.h"
28 : : #include "egg/egg-asn1-defs.h"
29 : : #include "egg/egg-dn.h"
30 : :
31 : : #include <glib/gi18n-lib.h>
32 : :
33 : : GBytes *
34 : 1 : _gcr_certificate_extension_find (GNode *cert,
35 : : GQuark oid,
36 : : gboolean *critical)
37 : : {
38 : : GNode *node;
39 : : gint index;
40 : :
41 [ - + ]: 1 : g_return_val_if_fail (cert != NULL, NULL);
42 : :
43 : : /* Extensions */
44 : 1 : for (index = 1; TRUE; ++index) {
45 : 5 : node = egg_asn1x_node (cert, "tbsCertificate", "extensions", index, NULL);
46 [ - + ]: 5 : if (node == NULL)
47 : 0 : return NULL;
48 : :
49 : : /* Dig out the OID */
50 [ + + ]: 5 : if (egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "extnID", NULL)) == oid) {
51 : :
52 [ - + ]: 1 : if (critical) {
53 [ # # ]: 0 : if (!egg_asn1x_get_boolean (egg_asn1x_node (node, "critical", NULL), critical))
54 : 0 : g_return_val_if_reached (NULL);
55 : : }
56 : :
57 : : /* Extension value */
58 : 1 : return egg_asn1x_get_string_as_bytes (egg_asn1x_node (node, "extnValue", NULL));
59 : : }
60 : : }
61 : :
62 : : g_assert_not_reached ();
63 : : }
64 : :
65 : : gboolean
66 : 2 : _gcr_certificate_extension_basic_constraints (GBytes *data,
67 : : gboolean *is_ca,
68 : : gint *path_len)
69 : : {
70 : 2 : gboolean ret = TRUE;
71 : 2 : GNode *asn = NULL;
72 : : GNode *node;
73 : : gulong value;
74 : :
75 [ - + ]: 2 : g_return_val_if_fail (data != NULL, FALSE);
76 : :
77 : 2 : asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "BasicConstraints", data);
78 [ - + ]: 2 : if (asn == NULL)
79 : 0 : return FALSE;
80 : :
81 [ + - ]: 2 : if (path_len) {
82 : 2 : node = egg_asn1x_node (asn, "pathLenConstraint", NULL);
83 [ + - ]: 2 : if (!egg_asn1x_have (node))
84 : 2 : *path_len = -1;
85 [ # # ]: 0 : else if (!egg_asn1x_get_integer_as_ulong (node, &value))
86 : 0 : ret = FALSE;
87 : : else
88 : 0 : *path_len = value;
89 : : }
90 : :
91 [ + - ]: 2 : if (is_ca) {
92 : 2 : node = egg_asn1x_node (asn, "cA", NULL);
93 [ + - ]: 2 : if (!egg_asn1x_have (node))
94 : 2 : *is_ca = FALSE;
95 [ # # ]: 0 : else if (!egg_asn1x_get_boolean (node, is_ca))
96 : 0 : ret = FALSE;
97 : : }
98 : :
99 : 2 : egg_asn1x_destroy (asn);
100 : 2 : return ret;
101 : : }
102 : :
103 : : GQuark *
104 : 1 : _gcr_certificate_extension_extended_key_usage (GBytes *data)
105 : : {
106 : 1 : GNode *asn = NULL;
107 : : GNode *node;
108 : : GArray *array;
109 : : GQuark oid;
110 : : int i;
111 : :
112 [ - + ]: 1 : g_return_val_if_fail (data != NULL, NULL);
113 : :
114 : 1 : asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "ExtKeyUsageSyntax", data);
115 [ - + ]: 1 : if (asn == NULL)
116 : 0 : return NULL;
117 : :
118 : 1 : array = g_array_new (TRUE, TRUE, sizeof (GQuark));
119 : 1 : for (i = 0; TRUE; ++i) {
120 : 3 : node = egg_asn1x_node (asn, i + 1, NULL);
121 [ + + ]: 3 : if (node == NULL)
122 : 1 : break;
123 : 2 : oid = egg_asn1x_get_oid_as_quark (node);
124 : 2 : g_array_append_val (array, oid);
125 : : }
126 : :
127 : 1 : egg_asn1x_destroy (asn);
128 : 1 : return (GQuark*)g_array_free (array, FALSE);
129 : : }
130 : :
131 : : gpointer
132 : 1 : _gcr_certificate_extension_subject_key_identifier (GBytes *data,
133 : : gsize *n_keyid)
134 : : {
135 : 1 : GNode *asn = NULL;
136 : : gpointer result;
137 : :
138 [ - + ]: 1 : g_return_val_if_fail (data != NULL, NULL);
139 : :
140 : 1 : asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectKeyIdentifier", data);
141 [ - + ]: 1 : if (asn == NULL)
142 : 0 : return NULL;
143 : :
144 : 1 : result = egg_asn1x_get_string_as_raw (asn, g_realloc, n_keyid);
145 : 1 : egg_asn1x_destroy (asn);
146 : :
147 : 1 : return result;
148 : : }
149 : :
150 : : static gulong
151 : 2 : _gcr_reverse_bits(gulong num, guint n_bits)
152 : : {
153 : 2 : gulong reverse_num = 0;
154 : : guint i;
155 [ + + ]: 19 : for (i = 0; i < n_bits; i++) {
156 [ + + ]: 17 : if ((num & (1 << i)))
157 : 6 : reverse_num |= 1 << ((n_bits - 1) - i);
158 : : }
159 : 2 : return reverse_num;
160 : : }
161 : :
162 : : gboolean
163 : 2 : _gcr_certificate_extension_key_usage (GBytes *data,
164 : : gulong *key_usage)
165 : : {
166 : 2 : GNode *asn = NULL;
167 : 2 : gboolean ret = TRUE;
168 : : guint n_bits;
169 : :
170 [ - + ]: 2 : g_return_val_if_fail (data != NULL, FALSE);
171 : :
172 : 2 : asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "KeyUsage", data);
173 [ - + ]: 2 : if (asn == NULL)
174 : 0 : return FALSE;
175 : :
176 : 2 : ret = egg_asn1x_get_bits_as_ulong (asn, key_usage, &n_bits);
177 : 2 : egg_asn1x_destroy (asn);
178 : 2 : *key_usage = _gcr_reverse_bits(*key_usage, n_bits);
179 : 2 : return ret;
180 : : }
181 : :
182 : : static void
183 : 2 : general_name_parse_other (GNode *node, GcrGeneralName *general)
184 : : {
185 : 2 : GNode *decode = NULL;
186 : : GQuark oid;
187 : : GNode *any;
188 : :
189 : 2 : general->type = GCR_GENERAL_NAME_OTHER;
190 : 2 : general->description = _("Other Name");
191 : 2 : general->display = NULL;
192 : :
193 : 2 : oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "type-id", NULL));
194 : 2 : any = egg_asn1x_node (node, "value", NULL);
195 : :
196 [ - + ]: 2 : if (any == NULL)
197 : 0 : return;
198 : :
199 [ + + ]: 2 : if (oid == GCR_OID_ALT_NAME_XMPP_ADDR) {
200 : 1 : general->description = _("XMPP Addr");
201 : 1 : decode = egg_asn1x_get_any_as_string (any, EGG_ASN1X_UTF8_STRING);
202 : 1 : general->display = egg_asn1x_get_string_as_utf8 (decode, g_realloc);
203 [ + - ]: 1 : } else if (oid == GCR_OID_ALT_NAME_DNS_SRV) {
204 : 1 : general->description = _("DNS SRV");
205 : 1 : decode = egg_asn1x_get_any_as_string (any, EGG_ASN1X_IA5_STRING);
206 : 1 : general->display = egg_asn1x_get_string_as_utf8 (decode, g_realloc);
207 : : }
208 : :
209 : 2 : egg_asn1x_destroy (decode);
210 : : }
211 : :
212 : : static void
213 : 0 : general_name_parse_rfc822 (GNode *node, GcrGeneralName *general)
214 : : {
215 : 0 : general->type = GCR_GENERAL_NAME_RFC822;
216 : 0 : general->description = _("Email");
217 : 0 : general->display = egg_asn1x_get_string_as_utf8 (node, g_realloc);
218 : 0 : }
219 : :
220 : : static void
221 : 1 : general_name_parse_dns (GNode *node, GcrGeneralName *general)
222 : : {
223 : 1 : general->type = GCR_GENERAL_NAME_DNS;
224 : 1 : general->description = _("DNS");
225 : 1 : general->display = egg_asn1x_get_string_as_utf8 (node, g_realloc);
226 : 1 : }
227 : :
228 : : static void
229 : 0 : general_name_parse_x400 (GNode *node, GcrGeneralName *general)
230 : : {
231 : 0 : general->type = GCR_GENERAL_NAME_X400;
232 : 0 : general->description = _("X400 Address");
233 : 0 : }
234 : :
235 : : static void
236 : 0 : general_name_parse_dn (GNode *node, GcrGeneralName *general)
237 : : {
238 : 0 : general->type = GCR_GENERAL_NAME_DNS;
239 : 0 : general->description = _("Directory Name");
240 : 0 : general->display = egg_dn_read (node);
241 : 0 : }
242 : :
243 : : static void
244 : 0 : general_name_parse_edi (GNode *node, GcrGeneralName *general)
245 : : {
246 : 0 : general->type = GCR_GENERAL_NAME_EDI;
247 : 0 : general->description = _("EDI Party Name");
248 : 0 : }
249 : :
250 : : static void
251 : 0 : general_name_parse_uri (GNode *node, GcrGeneralName *general)
252 : : {
253 : 0 : general->type = GCR_GENERAL_NAME_URI;
254 : 0 : general->description = _("URI");
255 : 0 : general->display = egg_asn1x_get_string_as_utf8 (node, g_realloc);
256 : 0 : }
257 : :
258 : : static void
259 : 1 : general_name_parse_ip (GNode *node, GcrGeneralName *general)
260 : : {
261 : 1 : general->type = GCR_GENERAL_NAME_IP;
262 : 1 : general->description = _("IP Address");
263 : 1 : general->display = egg_asn1x_get_string_as_utf8 (node, g_realloc);
264 : 1 : }
265 : :
266 : : static void
267 : 0 : general_name_parse_registered (GNode *node, GcrGeneralName *general)
268 : : {
269 : 0 : general->type = GCR_GENERAL_NAME_REGISTERED_ID;
270 : 0 : general->description = _("Registered ID");
271 : 0 : general->display = egg_asn1x_get_oid_as_string (node);
272 : 0 : }
273 : :
274 : : GArray*
275 : 1 : _gcr_certificate_extension_subject_alt_name (GBytes *data)
276 : : {
277 : 1 : GNode *asn = NULL;
278 : : guint count, i;
279 : : const gchar *node_name;
280 : : GArray *names;
281 : : GcrGeneralName general;
282 : : GNode *choice;
283 : :
284 : 1 : asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectAltName", data);
285 [ - + ]: 1 : if (asn == NULL)
286 : 0 : return NULL;
287 : :
288 : 1 : names = g_array_new (FALSE, TRUE, sizeof (GcrGeneralName));
289 : 1 : count = egg_asn1x_count (asn);
290 : :
291 [ + + ]: 5 : for (i = 0; i < count; i++) {
292 : 4 : choice = egg_asn1x_get_choice (egg_asn1x_node (asn, i + 1, NULL));
293 [ - + ]: 4 : g_return_val_if_fail (choice, NULL);
294 : :
295 : 4 : node_name = egg_asn1x_name (choice);
296 [ - + ]: 4 : g_return_val_if_fail (node_name, NULL);
297 : :
298 : 4 : memset (&general, 0, sizeof (general));
299 : :
300 [ + + ]: 4 : if (g_str_equal (node_name, "otherName"))
301 : 2 : general_name_parse_other (choice, &general);
302 : :
303 [ - + ]: 2 : else if (g_str_equal (node_name, "rfc822Name"))
304 : 0 : general_name_parse_rfc822 (choice, &general);
305 : :
306 [ + + ]: 2 : else if (g_str_equal (node_name, "dNSName"))
307 : 1 : general_name_parse_dns (choice, &general);
308 : :
309 [ - + ]: 1 : else if (g_str_equal (node_name, "x400Address"))
310 : 0 : general_name_parse_x400 (choice, &general);
311 : :
312 [ - + ]: 1 : else if (g_str_equal (node_name, "directoryName"))
313 : 0 : general_name_parse_dn (choice, &general);
314 : :
315 [ - + ]: 1 : else if (g_str_equal (node_name, "ediPartyName"))
316 : 0 : general_name_parse_edi (choice, &general);
317 : :
318 [ - + ]: 1 : else if (g_str_equal (node_name, "uniformResourceIdentifier"))
319 : 0 : general_name_parse_uri (choice, &general);
320 : :
321 [ + - ]: 1 : else if (g_str_equal (node_name, "iPAddress"))
322 : 1 : general_name_parse_ip (choice, &general);
323 : :
324 [ # # ]: 0 : else if (g_str_equal (node_name, "registeredID"))
325 : 0 : general_name_parse_registered (choice, &general);
326 : :
327 : 4 : general.raw = egg_asn1x_get_element_raw (choice);
328 : 4 : g_array_append_val (names, general);
329 : : }
330 : :
331 : 1 : egg_asn1x_destroy (asn);
332 : 1 : return names;
333 : : }
334 : :
335 : : void
336 : 1 : _gcr_general_names_free (GArray *names)
337 : : {
338 : : GcrGeneralName *name;
339 : : guint i;
340 : :
341 [ + - + + ]: 5 : for (i = 0; names && i < names->len; i++) {
342 : 4 : name = &g_array_index (names, GcrGeneralName, i);
343 : 4 : g_free (name->display);
344 : 4 : g_bytes_unref (name->raw);
345 : : }
346 : 1 : g_array_free (names, TRUE);
347 : 1 : }
|