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 *
_gcr_certificate_extension_find(GNode * cert,GQuark oid,gboolean * critical)34 _gcr_certificate_extension_find (GNode *cert,
35 GQuark oid,
36 gboolean *critical)
37 {
38 GNode *node;
39 gint index;
40
41 g_return_val_if_fail (cert != NULL, NULL);
42
43 /* Extensions */
44 for (index = 1; TRUE; ++index) {
45 node = egg_asn1x_node (cert, "tbsCertificate", "extensions", index, NULL);
46 if (node == NULL)
47 return NULL;
48
49 /* Dig out the OID */
50 if (egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "extnID", NULL)) == oid) {
51
52 if (critical) {
53 if (!egg_asn1x_get_boolean (egg_asn1x_node (node, "critical", NULL), critical))
54 g_return_val_if_reached (NULL);
55 }
56
57 /* Extension value */
58 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
_gcr_certificate_extension_basic_constraints(GBytes * data,gboolean * is_ca,gint * path_len)66 _gcr_certificate_extension_basic_constraints (GBytes *data,
67 gboolean *is_ca,
68 gint *path_len)
69 {
70 gboolean ret = TRUE;
71 GNode *asn = NULL;
72 GNode *node;
73 gulong value;
74
75 g_return_val_if_fail (data != NULL, FALSE);
76
77 asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "BasicConstraints", data);
78 if (asn == NULL)
79 return FALSE;
80
81 if (path_len) {
82 node = egg_asn1x_node (asn, "pathLenConstraint", NULL);
83 if (!egg_asn1x_have (node))
84 *path_len = -1;
85 else if (!egg_asn1x_get_integer_as_ulong (node, &value))
86 ret = FALSE;
87 else
88 *path_len = value;
89 }
90
91 if (is_ca) {
92 node = egg_asn1x_node (asn, "cA", NULL);
93 if (!egg_asn1x_have (node))
94 *is_ca = FALSE;
95 else if (!egg_asn1x_get_boolean (node, is_ca))
96 ret = FALSE;
97 }
98
99 egg_asn1x_destroy (asn);
100 return ret;
101 }
102
103 GQuark *
_gcr_certificate_extension_extended_key_usage(GBytes * data)104 _gcr_certificate_extension_extended_key_usage (GBytes *data)
105 {
106 GNode *asn = NULL;
107 GNode *node;
108 GArray *array;
109 GQuark oid;
110 int i;
111
112 g_return_val_if_fail (data != NULL, NULL);
113
114 asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "ExtKeyUsageSyntax", data);
115 if (asn == NULL)
116 return NULL;
117
118 array = g_array_new (TRUE, TRUE, sizeof (GQuark));
119 for (i = 0; TRUE; ++i) {
120 node = egg_asn1x_node (asn, i + 1, NULL);
121 if (node == NULL)
122 break;
123 oid = egg_asn1x_get_oid_as_quark (node);
124 g_array_append_val (array, oid);
125 }
126
127 egg_asn1x_destroy (asn);
128 return (GQuark*)g_array_free (array, FALSE);
129 }
130
131 gpointer
_gcr_certificate_extension_subject_key_identifier(GBytes * data,gsize * n_keyid)132 _gcr_certificate_extension_subject_key_identifier (GBytes *data,
133 gsize *n_keyid)
134 {
135 GNode *asn = NULL;
136 gpointer result;
137
138 g_return_val_if_fail (data != NULL, NULL);
139
140 asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectKeyIdentifier", data);
141 if (asn == NULL)
142 return NULL;
143
144 result = egg_asn1x_get_string_as_raw (asn, g_realloc, n_keyid);
145 egg_asn1x_destroy (asn);
146
147 return result;
148 }
149
150 static gulong
_gcr_reverse_bits(gulong num,guint n_bits)151 _gcr_reverse_bits(gulong num, guint n_bits)
152 {
153 gulong reverse_num = 0;
154 guint i;
155 for (i = 0; i < n_bits; i++) {
156 if ((num & (1 << i)))
157 reverse_num |= 1 << ((n_bits - 1) - i);
158 }
159 return reverse_num;
160 }
161
162 gboolean
_gcr_certificate_extension_key_usage(GBytes * data,gulong * key_usage)163 _gcr_certificate_extension_key_usage (GBytes *data,
164 gulong *key_usage)
165 {
166 GNode *asn = NULL;
167 gboolean ret = TRUE;
168 guint n_bits;
169
170 g_return_val_if_fail (data != NULL, FALSE);
171
172 asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "KeyUsage", data);
173 if (asn == NULL)
174 return FALSE;
175
176 ret = egg_asn1x_get_bits_as_ulong (asn, key_usage, &n_bits);
177 egg_asn1x_destroy (asn);
178 *key_usage = _gcr_reverse_bits(*key_usage, n_bits);
179 return ret;
180 }
181
182 static void
general_name_parse_other(GNode * node,GcrGeneralName * general)183 general_name_parse_other (GNode *node, GcrGeneralName *general)
184 {
185 GNode *decode = NULL;
186 GQuark oid;
187 GNode *any;
188
189 general->type = GCR_GENERAL_NAME_OTHER;
190 general->description = _("Other Name");
191 general->display = NULL;
192
193 oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "type-id", NULL));
194 any = egg_asn1x_node (node, "value", NULL);
195
196 if (any == NULL)
197 return;
198
199 if (oid == GCR_OID_ALT_NAME_XMPP_ADDR) {
200 general->description = _("XMPP Addr");
201 decode = egg_asn1x_get_any_as_string (any, EGG_ASN1X_UTF8_STRING);
202 general->display = egg_asn1x_get_string_as_utf8 (decode, g_realloc);
203 } else if (oid == GCR_OID_ALT_NAME_DNS_SRV) {
204 general->description = _("DNS SRV");
205 decode = egg_asn1x_get_any_as_string (any, EGG_ASN1X_IA5_STRING);
206 general->display = egg_asn1x_get_string_as_utf8 (decode, g_realloc);
207 }
208
209 egg_asn1x_destroy (decode);
210 }
211
212 static void
general_name_parse_rfc822(GNode * node,GcrGeneralName * general)213 general_name_parse_rfc822 (GNode *node, GcrGeneralName *general)
214 {
215 general->type = GCR_GENERAL_NAME_RFC822;
216 general->description = _("Email");
217 general->display = egg_asn1x_get_string_as_utf8 (node, g_realloc);
218 }
219
220 static void
general_name_parse_dns(GNode * node,GcrGeneralName * general)221 general_name_parse_dns (GNode *node, GcrGeneralName *general)
222 {
223 general->type = GCR_GENERAL_NAME_DNS;
224 general->description = _("DNS");
225 general->display = egg_asn1x_get_string_as_utf8 (node, g_realloc);
226 }
227
228 static void
general_name_parse_x400(GNode * node,GcrGeneralName * general)229 general_name_parse_x400 (GNode *node, GcrGeneralName *general)
230 {
231 general->type = GCR_GENERAL_NAME_X400;
232 general->description = _("X400 Address");
233 }
234
235 static void
general_name_parse_dn(GNode * node,GcrGeneralName * general)236 general_name_parse_dn (GNode *node, GcrGeneralName *general)
237 {
238 general->type = GCR_GENERAL_NAME_DNS;
239 general->description = _("Directory Name");
240 general->display = egg_dn_read (node);
241 }
242
243 static void
general_name_parse_edi(GNode * node,GcrGeneralName * general)244 general_name_parse_edi (GNode *node, GcrGeneralName *general)
245 {
246 general->type = GCR_GENERAL_NAME_EDI;
247 general->description = _("EDI Party Name");
248 }
249
250 static void
general_name_parse_uri(GNode * node,GcrGeneralName * general)251 general_name_parse_uri (GNode *node, GcrGeneralName *general)
252 {
253 general->type = GCR_GENERAL_NAME_URI;
254 general->description = _("URI");
255 general->display = egg_asn1x_get_string_as_utf8 (node, g_realloc);
256 }
257
258 static void
general_name_parse_ip(GNode * node,GcrGeneralName * general)259 general_name_parse_ip (GNode *node, GcrGeneralName *general)
260 {
261 general->type = GCR_GENERAL_NAME_IP;
262 general->description = _("IP Address");
263 general->display = egg_asn1x_get_string_as_utf8 (node, g_realloc);
264 }
265
266 static void
general_name_parse_registered(GNode * node,GcrGeneralName * general)267 general_name_parse_registered (GNode *node, GcrGeneralName *general)
268 {
269 general->type = GCR_GENERAL_NAME_REGISTERED_ID;
270 general->description = _("Registered ID");
271 general->display = egg_asn1x_get_oid_as_string (node);
272 }
273
274 GArray*
_gcr_certificate_extension_subject_alt_name(GBytes * data)275 _gcr_certificate_extension_subject_alt_name (GBytes *data)
276 {
277 GNode *asn = NULL;
278 guint count, i;
279 const gchar *node_name;
280 GArray *names;
281 GcrGeneralName general;
282 GNode *choice;
283
284 asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectAltName", data);
285 if (asn == NULL)
286 return NULL;
287
288 names = g_array_new (FALSE, TRUE, sizeof (GcrGeneralName));
289 count = egg_asn1x_count (asn);
290
291 for (i = 0; i < count; i++) {
292 choice = egg_asn1x_get_choice (egg_asn1x_node (asn, i + 1, NULL));
293 g_return_val_if_fail (choice, NULL);
294
295 node_name = egg_asn1x_name (choice);
296 g_return_val_if_fail (node_name, NULL);
297
298 memset (&general, 0, sizeof (general));
299
300 if (g_str_equal (node_name, "otherName"))
301 general_name_parse_other (choice, &general);
302
303 else if (g_str_equal (node_name, "rfc822Name"))
304 general_name_parse_rfc822 (choice, &general);
305
306 else if (g_str_equal (node_name, "dNSName"))
307 general_name_parse_dns (choice, &general);
308
309 else if (g_str_equal (node_name, "x400Address"))
310 general_name_parse_x400 (choice, &general);
311
312 else if (g_str_equal (node_name, "directoryName"))
313 general_name_parse_dn (choice, &general);
314
315 else if (g_str_equal (node_name, "ediPartyName"))
316 general_name_parse_edi (choice, &general);
317
318 else if (g_str_equal (node_name, "uniformResourceIdentifier"))
319 general_name_parse_uri (choice, &general);
320
321 else if (g_str_equal (node_name, "iPAddress"))
322 general_name_parse_ip (choice, &general);
323
324 else if (g_str_equal (node_name, "registeredID"))
325 general_name_parse_registered (choice, &general);
326
327 general.raw = egg_asn1x_get_element_raw (choice);
328 g_array_append_val (names, general);
329 }
330
331 egg_asn1x_destroy (asn);
332 return names;
333 }
334
335 void
_gcr_general_names_free(GArray * names)336 _gcr_general_names_free (GArray *names)
337 {
338 GcrGeneralName *name;
339 guint i;
340
341 for (i = 0; names && i < names->len; i++) {
342 name = &g_array_index (names, GcrGeneralName, i);
343 g_free (name->display);
344 g_bytes_unref (name->raw);
345 }
346 g_array_free (names, TRUE);
347 }
348