/src/strongswan/src/libstrongswan/plugins/x509/x509_ac.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2017 Tobias Brunner |
3 | | * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler |
4 | | * Copyright (C) 2003 Martin Berner, Lukas Suter |
5 | | * Copyright (C) 2002-2022 Andreas Steffen |
6 | | * Copyright (C) 2009 Martin Willi |
7 | | * |
8 | | * Copyright (C) secunet Security Networks AG |
9 | | * |
10 | | * This program is free software; you can redistribute it and/or modify it |
11 | | * under the terms of the GNU General Public License as published by the |
12 | | * Free Software Foundation; either version 2 of the License, or (at your |
13 | | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. |
14 | | * |
15 | | * This program is distributed in the hope that it will be useful, but |
16 | | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
17 | | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
18 | | * for more details. |
19 | | */ |
20 | | |
21 | | #include "x509_ac.h" |
22 | | |
23 | | #include <time.h> |
24 | | |
25 | | #include <library.h> |
26 | | #include <utils/debug.h> |
27 | | #include <asn1/oid.h> |
28 | | #include <asn1/asn1.h> |
29 | | #include <asn1/asn1_parser.h> |
30 | | #include <utils/identification.h> |
31 | | #include <collections/linked_list.h> |
32 | | #include <credentials/certificates/x509.h> |
33 | | #include <credentials/keys/private_key.h> |
34 | | |
35 | | extern chunk_t x509_parse_authorityKeyIdentifier(chunk_t blob, |
36 | | int level0, chunk_t *authKeySerialNumber); |
37 | | |
38 | | typedef struct private_x509_ac_t private_x509_ac_t; |
39 | | |
40 | | /** |
41 | | * private data of x509_ac_t object |
42 | | */ |
43 | | struct private_x509_ac_t { |
44 | | |
45 | | /** |
46 | | * public functions |
47 | | */ |
48 | | x509_ac_t public; |
49 | | |
50 | | /** |
51 | | * X.509 attribute certificate encoding in ASN.1 DER format |
52 | | */ |
53 | | chunk_t encoding; |
54 | | |
55 | | /** |
56 | | * X.509 attribute certificate body over which signature is computed |
57 | | */ |
58 | | chunk_t certificateInfo; |
59 | | |
60 | | /** |
61 | | * Version of the X.509 attribute certificate |
62 | | */ |
63 | | u_int version; |
64 | | |
65 | | /** |
66 | | * Serial number of the X.509 attribute certificate |
67 | | */ |
68 | | chunk_t serialNumber; |
69 | | |
70 | | /** |
71 | | * ID representing the issuer of the holder certificate |
72 | | */ |
73 | | identification_t *holderIssuer; |
74 | | |
75 | | /** |
76 | | * Serial number of the holder certificate |
77 | | */ |
78 | | identification_t *holderSerial; |
79 | | |
80 | | /** |
81 | | * ID representing the holder |
82 | | */ |
83 | | identification_t *entityName; |
84 | | |
85 | | /** |
86 | | * ID representing the attribute certificate issuer |
87 | | */ |
88 | | identification_t *issuerName; |
89 | | |
90 | | /** |
91 | | * Start time of certificate validity |
92 | | */ |
93 | | time_t notBefore; |
94 | | |
95 | | /** |
96 | | * End time of certificate validity |
97 | | */ |
98 | | time_t notAfter; |
99 | | |
100 | | /** |
101 | | * List of group attributes, as group_t |
102 | | */ |
103 | | linked_list_t *groups; |
104 | | |
105 | | /** |
106 | | * Authority Key Identifier |
107 | | */ |
108 | | chunk_t authKeyIdentifier; |
109 | | |
110 | | /** |
111 | | * Authority Key Serial Number |
112 | | */ |
113 | | chunk_t authKeySerialNumber; |
114 | | |
115 | | /** |
116 | | * No revocation information available |
117 | | */ |
118 | | bool noRevAvail; |
119 | | |
120 | | /** |
121 | | * Signature scheme |
122 | | */ |
123 | | signature_params_t *scheme; |
124 | | |
125 | | /** |
126 | | * Signature |
127 | | */ |
128 | | chunk_t signature; |
129 | | |
130 | | /** |
131 | | * Holder certificate |
132 | | */ |
133 | | certificate_t *holderCert; |
134 | | |
135 | | /** |
136 | | * Signer certificate |
137 | | */ |
138 | | certificate_t *signerCert; |
139 | | |
140 | | /** |
141 | | * Signer private key; |
142 | | */ |
143 | | private_key_t *signerKey; |
144 | | |
145 | | /** |
146 | | * reference count |
147 | | */ |
148 | | refcount_t ref; |
149 | | }; |
150 | | |
151 | | /** |
152 | | * Group definition, an IETF attribute |
153 | | */ |
154 | | typedef struct { |
155 | | /** Attribute type */ |
156 | | ac_group_type_t type; |
157 | | /* attribute value */ |
158 | | chunk_t value; |
159 | | } group_t; |
160 | | |
161 | | /** |
162 | | * Clean up a group entry |
163 | | */ |
164 | | static void group_destroy(group_t *group) |
165 | 0 | { |
166 | 0 | free(group->value.ptr); |
167 | 0 | free(group); |
168 | 0 | } |
169 | | |
170 | | static chunk_t ASN1_noRevAvail_ext = chunk_from_chars( |
171 | | 0x30, 0x09, |
172 | | 0x06, 0x03, |
173 | | 0x55, 0x1d, 0x38, |
174 | | 0x04, 0x02, |
175 | | 0x05, 0x00 |
176 | | ); |
177 | | |
178 | | /** |
179 | | * declaration of function implemented in x509_cert.c |
180 | | */ |
181 | | extern bool x509_parse_generalNames(chunk_t blob, int level0, bool implicit, |
182 | | linked_list_t *list); |
183 | | /** |
184 | | * parses a directoryName |
185 | | */ |
186 | | static bool parse_directoryName(chunk_t blob, int level, bool implicit, |
187 | | identification_t **name) |
188 | 0 | { |
189 | 0 | identification_t *directoryName; |
190 | 0 | enumerator_t *enumerator; |
191 | 0 | bool first = TRUE; |
192 | 0 | linked_list_t *list; |
193 | |
|
194 | 0 | list = linked_list_create(); |
195 | 0 | if (!x509_parse_generalNames(blob, level, implicit, list)) |
196 | 0 | { |
197 | 0 | list->destroy(list); |
198 | 0 | return FALSE; |
199 | 0 | } |
200 | | |
201 | 0 | enumerator = list->create_enumerator(list); |
202 | 0 | while (enumerator->enumerate(enumerator, &directoryName)) |
203 | 0 | { |
204 | 0 | if (first) |
205 | 0 | { |
206 | 0 | *name = directoryName; |
207 | 0 | first = FALSE; |
208 | 0 | } |
209 | 0 | else |
210 | 0 | { |
211 | 0 | DBG1(DBG_ASN, "more than one directory name - first selected"); |
212 | 0 | directoryName->destroy(directoryName); |
213 | 0 | break; |
214 | 0 | } |
215 | 0 | } |
216 | 0 | enumerator->destroy(enumerator); |
217 | 0 | list->destroy(list); |
218 | |
|
219 | 0 | if (first) |
220 | 0 | { |
221 | 0 | DBG1(DBG_ASN, "no directoryName found"); |
222 | 0 | return FALSE; |
223 | 0 | } |
224 | 0 | return TRUE; |
225 | 0 | } |
226 | | |
227 | | /** |
228 | | * ASN.1 definition of roleSyntax |
229 | | */ |
230 | | static const asn1Object_t roleSyntaxObjects[] = |
231 | | { |
232 | | { 0, "roleSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ |
233 | | { 1, "roleAuthority", ASN1_CONTEXT_C_0, ASN1_OPT | |
234 | | ASN1_OBJ }, /* 1 */ |
235 | | { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ |
236 | | { 1, "roleName", ASN1_CONTEXT_C_1, ASN1_OBJ }, /* 3 */ |
237 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
238 | | }; |
239 | | |
240 | | /** |
241 | | * Parses roleSyntax |
242 | | */ |
243 | | static void parse_roleSyntax(chunk_t blob, int level0) |
244 | 0 | { |
245 | 0 | asn1_parser_t *parser; |
246 | 0 | chunk_t object; |
247 | 0 | int objectID; |
248 | |
|
249 | 0 | parser = asn1_parser_create(roleSyntaxObjects, blob); |
250 | 0 | parser->set_top_level(parser, level0); |
251 | |
|
252 | 0 | while (parser->iterate(parser, &objectID, &object)) |
253 | 0 | { |
254 | 0 | switch (objectID) |
255 | 0 | { |
256 | 0 | default: |
257 | 0 | break; |
258 | 0 | } |
259 | 0 | } |
260 | 0 | parser->destroy(parser); |
261 | 0 | } |
262 | | |
263 | | /** |
264 | | * ASN.1 definition of ietfAttrSyntax |
265 | | */ |
266 | | static const asn1Object_t ietfAttrSyntaxObjects[] = |
267 | | { |
268 | | { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ |
269 | | { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT | |
270 | | ASN1_BODY }, /* 1 */ |
271 | | { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ |
272 | | { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */ |
273 | | { 2, "octets", ASN1_OCTET_STRING, ASN1_OPT | |
274 | | ASN1_BODY }, /* 4 */ |
275 | | { 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ |
276 | | { 2, "oid", ASN1_OID, ASN1_OPT | |
277 | | ASN1_BODY }, /* 6 */ |
278 | | { 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ |
279 | | { 2, "string", ASN1_UTF8STRING, ASN1_OPT | |
280 | | ASN1_BODY }, /* 8 */ |
281 | | { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ |
282 | | { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */ |
283 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
284 | | }; |
285 | 0 | #define IETF_ATTR_OCTETS 4 |
286 | 0 | #define IETF_ATTR_OID 6 |
287 | 0 | #define IETF_ATTR_STRING 8 |
288 | | |
289 | | /** |
290 | | * Parse group memberships, IETF attributes |
291 | | */ |
292 | | static bool parse_groups(private_x509_ac_t *this, chunk_t encoded, int level0) |
293 | 0 | { |
294 | 0 | ac_group_type_t type; |
295 | 0 | group_t *group; |
296 | 0 | asn1_parser_t *parser; |
297 | 0 | chunk_t object; |
298 | 0 | int objectID; |
299 | 0 | bool success; |
300 | |
|
301 | 0 | parser = asn1_parser_create(ietfAttrSyntaxObjects, encoded); |
302 | 0 | parser->set_top_level(parser, level0); |
303 | 0 | while (parser->iterate(parser, &objectID, &object)) |
304 | 0 | { |
305 | 0 | switch (objectID) |
306 | 0 | { |
307 | 0 | case IETF_ATTR_OCTETS: |
308 | 0 | type = AC_GROUP_TYPE_OCTETS; |
309 | 0 | break; |
310 | 0 | case IETF_ATTR_OID: |
311 | 0 | type = AC_GROUP_TYPE_OID; |
312 | 0 | break; |
313 | 0 | case IETF_ATTR_STRING: |
314 | 0 | type = AC_GROUP_TYPE_STRING; |
315 | 0 | break; |
316 | 0 | default: |
317 | 0 | continue; |
318 | 0 | } |
319 | 0 | INIT(group, |
320 | 0 | .type = type, |
321 | 0 | .value = chunk_clone(object), |
322 | 0 | ); |
323 | 0 | this->groups->insert_last(this->groups, group); |
324 | 0 | } |
325 | 0 | success = parser->success(parser); |
326 | 0 | parser->destroy(parser); |
327 | |
|
328 | 0 | return success; |
329 | 0 | } |
330 | | |
331 | | /** |
332 | | * ASN.1 definition of an X509 attribute certificate |
333 | | */ |
334 | | static const asn1Object_t acObjects[] = |
335 | | { |
336 | | { 0, "AttributeCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ |
337 | | { 1, "AttributeCertificateInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ |
338 | | { 2, "version", ASN1_INTEGER, ASN1_DEF | |
339 | | ASN1_BODY }, /* 2 */ |
340 | | { 2, "holder", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */ |
341 | | { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */ |
342 | | { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ |
343 | | { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 6 */ |
344 | | { 4, "issuerUID", ASN1_BIT_STRING, ASN1_OPT | |
345 | | ASN1_BODY }, /* 7 */ |
346 | | { 4, "end opt", ASN1_EOC, ASN1_END }, /* 8 */ |
347 | | { 3, "end opt", ASN1_EOC, ASN1_END }, /* 9 */ |
348 | | { 3, "entityName", ASN1_CONTEXT_C_1, ASN1_OPT | |
349 | | ASN1_OBJ }, /* 10 */ |
350 | | { 3, "end opt", ASN1_EOC, ASN1_END }, /* 11 */ |
351 | | { 3, "objectDigestInfo", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 12 */ |
352 | | { 4, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 13 */ |
353 | | { 4, "otherObjectTypeID", ASN1_OID, ASN1_OPT | |
354 | | ASN1_BODY }, /* 14 */ |
355 | | { 4, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ |
356 | | { 4, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 16 */ |
357 | | { 3, "end opt", ASN1_EOC, ASN1_END }, /* 17 */ |
358 | | { 2, "v2Form", ASN1_CONTEXT_C_0, ASN1_NONE }, /* 18 */ |
359 | | { 3, "issuerName", ASN1_SEQUENCE, ASN1_OPT | |
360 | | ASN1_OBJ }, /* 19 */ |
361 | | { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */ |
362 | | { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 21 */ |
363 | | { 4, "issuerSerial", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */ |
364 | | { 5, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 23 */ |
365 | | { 5, "serial", ASN1_INTEGER, ASN1_BODY }, /* 24 */ |
366 | | { 5, "issuerUID", ASN1_BIT_STRING, ASN1_OPT | |
367 | | ASN1_BODY }, /* 25 */ |
368 | | { 5, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ |
369 | | { 3, "end opt", ASN1_EOC, ASN1_END }, /* 27 */ |
370 | | { 3, "objectDigestInfo", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 28 */ |
371 | | { 4, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 29 */ |
372 | | { 5, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 30 */ |
373 | | { 5, "otherObjectTypeID", ASN1_OID, ASN1_OPT | |
374 | | ASN1_BODY }, /* 31 */ |
375 | | { 5, "end opt", ASN1_EOC, ASN1_END }, /* 32 */ |
376 | | { 5, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 33 */ |
377 | | { 3, "end opt", ASN1_EOC, ASN1_END }, /* 34 */ |
378 | | { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 35 */ |
379 | | { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 36 */ |
380 | | { 2, "attrCertValidityPeriod", ASN1_SEQUENCE, ASN1_NONE }, /* 37 */ |
381 | | { 3, "notBeforeTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 38 */ |
382 | | { 3, "notAfterTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 39 */ |
383 | | { 2, "attributes", ASN1_SEQUENCE, ASN1_LOOP }, /* 40 */ |
384 | | { 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 41 */ |
385 | | { 4, "type", ASN1_OID, ASN1_BODY }, /* 42 */ |
386 | | { 4, "values", ASN1_SET, ASN1_LOOP }, /* 43 */ |
387 | | { 5, "value", ASN1_EOC, ASN1_RAW }, /* 44 */ |
388 | | { 4, "end loop", ASN1_EOC, ASN1_END }, /* 45 */ |
389 | | { 2, "end loop", ASN1_EOC, ASN1_END }, /* 46 */ |
390 | | { 2, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 47 */ |
391 | | { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 48 */ |
392 | | { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 49 */ |
393 | | { 4, "critical", ASN1_BOOLEAN, ASN1_DEF | |
394 | | ASN1_BODY }, /* 50 */ |
395 | | { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 51 */ |
396 | | { 2, "end loop", ASN1_EOC, ASN1_END }, /* 52 */ |
397 | | { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 53 */ |
398 | | { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 54 */ |
399 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
400 | | }; |
401 | 0 | #define AC_OBJ_CERTIFICATE_INFO 1 |
402 | 0 | #define AC_OBJ_VERSION 2 |
403 | 0 | #define AC_OBJ_HOLDER_ISSUER 5 |
404 | 0 | #define AC_OBJ_HOLDER_SERIAL 6 |
405 | 0 | #define AC_OBJ_ENTITY_NAME 10 |
406 | 0 | #define AC_OBJ_ISSUER_NAME 19 |
407 | | #define AC_OBJ_ISSUER 23 |
408 | 0 | #define AC_OBJ_SIG_ALG 35 |
409 | 0 | #define AC_OBJ_SERIAL_NUMBER 36 |
410 | 0 | #define AC_OBJ_NOT_BEFORE 38 |
411 | 0 | #define AC_OBJ_NOT_AFTER 39 |
412 | 0 | #define AC_OBJ_ATTRIBUTE_TYPE 42 |
413 | 0 | #define AC_OBJ_ATTRIBUTE_VALUE 44 |
414 | 0 | #define AC_OBJ_EXTN_ID 49 |
415 | 0 | #define AC_OBJ_CRITICAL 50 |
416 | 0 | #define AC_OBJ_EXTN_VALUE 51 |
417 | 0 | #define AC_OBJ_ALGORITHM 53 |
418 | 0 | #define AC_OBJ_SIGNATURE 54 |
419 | | |
420 | | /** |
421 | | * Parses an X.509 attribute certificate |
422 | | */ |
423 | | static bool parse_certificate(private_x509_ac_t *this) |
424 | 0 | { |
425 | 0 | asn1_parser_t *parser; |
426 | 0 | chunk_t object; |
427 | 0 | int objectID; |
428 | 0 | int type = OID_UNKNOWN; |
429 | 0 | int extn_oid = OID_UNKNOWN; |
430 | 0 | signature_params_t sig_alg = {}; |
431 | 0 | bool success = FALSE; |
432 | |
|
433 | 0 | parser = asn1_parser_create(acObjects, this->encoding); |
434 | |
|
435 | 0 | while (parser->iterate(parser, &objectID, &object)) |
436 | 0 | { |
437 | 0 | u_int level = parser->get_level(parser)+1; |
438 | |
|
439 | 0 | switch (objectID) |
440 | 0 | { |
441 | 0 | case AC_OBJ_CERTIFICATE_INFO: |
442 | 0 | this->certificateInfo = object; |
443 | 0 | break; |
444 | 0 | case AC_OBJ_VERSION: |
445 | 0 | this->version = (object.len) ? (1 + (u_int)*object.ptr) : 1; |
446 | 0 | DBG2(DBG_ASN, " v%d", this->version); |
447 | 0 | if (this->version != 2) |
448 | 0 | { |
449 | 0 | DBG1(DBG_ASN, "v%d attribute certificates are not " |
450 | 0 | "supported", this->version); |
451 | 0 | goto end; |
452 | 0 | } |
453 | 0 | break; |
454 | 0 | case AC_OBJ_HOLDER_ISSUER: |
455 | 0 | if (!parse_directoryName(object, level, FALSE, |
456 | 0 | &this->holderIssuer)) |
457 | 0 | { |
458 | 0 | goto end; |
459 | 0 | } |
460 | 0 | break; |
461 | 0 | case AC_OBJ_HOLDER_SERIAL: |
462 | 0 | this->holderSerial = identification_create_from_encoding( |
463 | 0 | ID_KEY_ID, chunk_skip_zero(object)); |
464 | 0 | break; |
465 | 0 | case AC_OBJ_ENTITY_NAME: |
466 | 0 | if (!parse_directoryName(object, level, TRUE, |
467 | 0 | &this->entityName)) |
468 | 0 | { |
469 | 0 | goto end; |
470 | 0 | } |
471 | 0 | break; |
472 | 0 | case AC_OBJ_ISSUER_NAME: |
473 | 0 | if (!parse_directoryName(object, level, FALSE, |
474 | 0 | &this->issuerName)) |
475 | 0 | { |
476 | 0 | goto end; |
477 | 0 | } |
478 | 0 | break; |
479 | 0 | case AC_OBJ_SIG_ALG: |
480 | 0 | if (!signature_params_parse(object, level, &sig_alg)) |
481 | 0 | { |
482 | 0 | DBG1(DBG_ASN, " unable to parse signature algorithm"); |
483 | 0 | goto end; |
484 | 0 | } |
485 | 0 | break; |
486 | 0 | case AC_OBJ_SERIAL_NUMBER: |
487 | 0 | this->serialNumber = chunk_clone(object); |
488 | 0 | break; |
489 | 0 | case AC_OBJ_NOT_BEFORE: |
490 | 0 | this->notBefore = asn1_to_time(&object, ASN1_GENERALIZEDTIME); |
491 | 0 | break; |
492 | 0 | case AC_OBJ_NOT_AFTER: |
493 | 0 | this->notAfter = asn1_to_time(&object, ASN1_GENERALIZEDTIME); |
494 | 0 | break; |
495 | 0 | case AC_OBJ_ATTRIBUTE_TYPE: |
496 | 0 | type = asn1_known_oid(object); |
497 | 0 | break; |
498 | 0 | case AC_OBJ_ATTRIBUTE_VALUE: |
499 | 0 | { |
500 | 0 | switch (type) |
501 | 0 | { |
502 | 0 | case OID_AUTHENTICATION_INFO: |
503 | 0 | DBG2(DBG_ASN, " need to parse authenticationInfo"); |
504 | 0 | break; |
505 | 0 | case OID_ACCESS_IDENTITY: |
506 | 0 | DBG2(DBG_ASN, " need to parse accessIdentity"); |
507 | 0 | break; |
508 | 0 | case OID_CHARGING_IDENTITY: |
509 | 0 | DBG2(DBG_ASN, " need to parse chargingIdentity"); |
510 | 0 | break; |
511 | 0 | case OID_GROUP: |
512 | 0 | DBG2(DBG_ASN, "-- > --"); |
513 | 0 | if (!parse_groups(this, object, level)) |
514 | 0 | { |
515 | 0 | goto end; |
516 | 0 | } |
517 | 0 | DBG2(DBG_ASN, "-- < --"); |
518 | 0 | break; |
519 | 0 | case OID_ROLE: |
520 | 0 | parse_roleSyntax(object, level); |
521 | 0 | break; |
522 | 0 | default: |
523 | 0 | break; |
524 | 0 | } |
525 | 0 | break; |
526 | 0 | } |
527 | 0 | case AC_OBJ_EXTN_ID: |
528 | 0 | extn_oid = asn1_known_oid(object); |
529 | 0 | break; |
530 | 0 | case AC_OBJ_CRITICAL: |
531 | 0 | DBG2(DBG_ASN, " %s", |
532 | 0 | object.len && *object.ptr ? "TRUE" : "FALSE"); |
533 | 0 | break; |
534 | 0 | case AC_OBJ_EXTN_VALUE: |
535 | 0 | { |
536 | 0 | switch (extn_oid) |
537 | 0 | { |
538 | 0 | case OID_CRL_DISTRIBUTION_POINTS: |
539 | 0 | DBG2(DBG_ASN, " need to parse crlDistributionPoints"); |
540 | 0 | break; |
541 | 0 | case OID_AUTHORITY_KEY_ID: |
542 | 0 | this->authKeyIdentifier = |
543 | 0 | x509_parse_authorityKeyIdentifier(object, |
544 | 0 | level, &this->authKeySerialNumber); |
545 | 0 | break; |
546 | 0 | case OID_TARGET_INFORMATION: |
547 | 0 | DBG2(DBG_ASN, " need to parse targetInformation"); |
548 | 0 | break; |
549 | 0 | case OID_NO_REV_AVAIL: |
550 | 0 | this->noRevAvail = TRUE; |
551 | 0 | break; |
552 | 0 | default: |
553 | 0 | break; |
554 | 0 | } |
555 | 0 | break; |
556 | 0 | } |
557 | 0 | case AC_OBJ_ALGORITHM: |
558 | 0 | INIT(this->scheme); |
559 | 0 | if (!signature_params_parse(object, level, this->scheme)) |
560 | 0 | { |
561 | 0 | DBG1(DBG_ASN, " unable to parse signature algorithm"); |
562 | 0 | goto end; |
563 | 0 | } |
564 | 0 | if (!signature_params_equal(this->scheme, &sig_alg)) |
565 | 0 | { |
566 | 0 | DBG1(DBG_ASN, " signature algorithms do not agree"); |
567 | 0 | goto end; |
568 | 0 | } |
569 | 0 | break; |
570 | 0 | case AC_OBJ_SIGNATURE: |
571 | 0 | this->signature = chunk_skip(object, 1); |
572 | 0 | break; |
573 | 0 | default: |
574 | 0 | break; |
575 | 0 | } |
576 | 0 | } |
577 | 0 | success = parser->success(parser); |
578 | |
|
579 | 0 | end: |
580 | 0 | parser->destroy(parser); |
581 | 0 | signature_params_clear(&sig_alg); |
582 | 0 | return success; |
583 | 0 | } |
584 | | |
585 | | /** |
586 | | * build directoryName |
587 | | */ |
588 | | static chunk_t build_directoryName(asn1_t tag, chunk_t name) |
589 | 0 | { |
590 | 0 | return asn1_wrap(tag, "m", |
591 | 0 | asn1_simple_object(ASN1_CONTEXT_C_4, name)); |
592 | 0 | } |
593 | | |
594 | | /** |
595 | | * build holder |
596 | | */ |
597 | | static chunk_t build_holder(private_x509_ac_t *this) |
598 | 0 | { |
599 | 0 | x509_t* x509 = (x509_t*)this->holderCert; |
600 | 0 | identification_t *issuer, *subject; |
601 | |
|
602 | 0 | this->holderSerial = identification_create_from_encoding( |
603 | 0 | ID_KEY_ID, x509->get_serial(x509)); |
604 | |
|
605 | 0 | issuer = this->holderCert->get_issuer(this->holderCert); |
606 | 0 | subject = this->holderCert->get_subject(this->holderCert); |
607 | |
|
608 | 0 | return asn1_wrap(ASN1_SEQUENCE, "mm", |
609 | 0 | asn1_wrap(ASN1_CONTEXT_C_0, "mm", |
610 | 0 | build_directoryName(ASN1_SEQUENCE, issuer->get_encoding(issuer)), |
611 | 0 | asn1_integer("c", x509->get_serial(x509))), |
612 | 0 | build_directoryName(ASN1_CONTEXT_C_1, subject->get_encoding(subject))); |
613 | 0 | } |
614 | | |
615 | | /** |
616 | | * build v2Form |
617 | | */ |
618 | | static chunk_t build_v2_form(private_x509_ac_t *this) |
619 | 0 | { |
620 | 0 | identification_t *subject; |
621 | |
|
622 | 0 | subject = this->signerCert->get_subject(this->signerCert); |
623 | 0 | return asn1_wrap(ASN1_CONTEXT_C_0, "m", |
624 | 0 | build_directoryName(ASN1_SEQUENCE, |
625 | 0 | subject->get_encoding(subject))); |
626 | 0 | } |
627 | | |
628 | | /** |
629 | | * build attrCertValidityPeriod |
630 | | */ |
631 | | static chunk_t build_attr_cert_validity(private_x509_ac_t *this) |
632 | 0 | { |
633 | 0 | return asn1_wrap(ASN1_SEQUENCE, "mm", |
634 | 0 | asn1_from_time(&this->notBefore, ASN1_GENERALIZEDTIME), |
635 | 0 | asn1_from_time(&this->notAfter, ASN1_GENERALIZEDTIME)); |
636 | 0 | } |
637 | | |
638 | | /** |
639 | | * build attribute type |
640 | | */ |
641 | | static chunk_t build_attribute_type(int type, chunk_t content) |
642 | 0 | { |
643 | 0 | return asn1_wrap(ASN1_SEQUENCE, "mm", |
644 | 0 | asn1_build_known_oid(type), |
645 | 0 | asn1_wrap(ASN1_SET, "m", content)); |
646 | 0 | } |
647 | | |
648 | | /** |
649 | | * build attributes |
650 | | */ |
651 | | static chunk_t build_attributes(private_x509_ac_t *this) |
652 | 0 | { |
653 | 0 | enumerator_t *enumerator; |
654 | 0 | group_t *group; |
655 | 0 | chunk_t values; |
656 | 0 | size_t size = 0, len; |
657 | 0 | u_char *pos; |
658 | | |
659 | | /* precalculate the total size of all values */ |
660 | 0 | enumerator = this->groups->create_enumerator(this->groups); |
661 | 0 | while (enumerator->enumerate(enumerator, &group)) |
662 | 0 | { |
663 | 0 | len = group->value.len; |
664 | 0 | size += 1 + (len > 0) + (len >= 128) + |
665 | 0 | (len >= 256) + (len >= 65536) + len; |
666 | 0 | } |
667 | 0 | enumerator->destroy(enumerator); |
668 | |
|
669 | 0 | pos = asn1_build_object(&values, ASN1_SEQUENCE, size); |
670 | |
|
671 | 0 | enumerator = this->groups->create_enumerator(this->groups); |
672 | 0 | while (enumerator->enumerate(enumerator, &group)) |
673 | 0 | { |
674 | 0 | chunk_t attr; |
675 | 0 | asn1_t type; |
676 | |
|
677 | 0 | switch (group->type) |
678 | 0 | { |
679 | 0 | case AC_GROUP_TYPE_OCTETS: |
680 | 0 | type = ASN1_OCTET_STRING; |
681 | 0 | break; |
682 | 0 | case AC_GROUP_TYPE_STRING: |
683 | 0 | type = ASN1_UTF8STRING; |
684 | 0 | break; |
685 | 0 | case AC_GROUP_TYPE_OID: |
686 | 0 | type = ASN1_OID; |
687 | 0 | break; |
688 | 0 | default: |
689 | 0 | continue; |
690 | 0 | } |
691 | 0 | attr = asn1_simple_object(type, group->value); |
692 | |
|
693 | 0 | memcpy(pos, attr.ptr, attr.len); |
694 | 0 | pos += attr.len; |
695 | 0 | free(attr.ptr); |
696 | 0 | } |
697 | 0 | enumerator->destroy(enumerator); |
698 | |
|
699 | 0 | return asn1_wrap(ASN1_SEQUENCE, "m", |
700 | 0 | build_attribute_type(OID_GROUP, |
701 | 0 | asn1_wrap(ASN1_SEQUENCE, "m", values))); |
702 | 0 | } |
703 | | |
704 | | /** |
705 | | * build authorityKeyIdentifier |
706 | | */ |
707 | | static chunk_t build_authorityKeyIdentifier(private_x509_ac_t *this) |
708 | 0 | { |
709 | 0 | chunk_t keyIdentifier = chunk_empty; |
710 | 0 | chunk_t authorityCertIssuer; |
711 | 0 | chunk_t authorityCertSerialNumber; |
712 | 0 | identification_t *issuer; |
713 | 0 | public_key_t *public; |
714 | 0 | x509_t *x509; |
715 | |
|
716 | 0 | x509 = (x509_t*)this->signerCert; |
717 | 0 | issuer = this->signerCert->get_issuer(this->signerCert); |
718 | 0 | public = this->signerCert->get_public_key(this->signerCert); |
719 | 0 | if (public) |
720 | 0 | { |
721 | 0 | if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &keyIdentifier)) |
722 | 0 | { |
723 | 0 | this->authKeyIdentifier = chunk_clone(keyIdentifier); |
724 | 0 | keyIdentifier = asn1_simple_object(ASN1_CONTEXT_S_0, keyIdentifier); |
725 | 0 | } |
726 | 0 | public->destroy(public); |
727 | 0 | } |
728 | 0 | authorityCertIssuer = build_directoryName(ASN1_CONTEXT_C_1, |
729 | 0 | issuer->get_encoding(issuer)); |
730 | 0 | authorityCertSerialNumber = asn1_integer("c", x509->get_serial(x509)); |
731 | 0 | authorityCertSerialNumber.ptr[0] = ASN1_CONTEXT_S_2; |
732 | 0 | return asn1_wrap(ASN1_SEQUENCE, "mm", |
733 | 0 | asn1_build_known_oid(OID_AUTHORITY_KEY_ID), |
734 | 0 | asn1_wrap(ASN1_OCTET_STRING, "m", |
735 | 0 | asn1_wrap(ASN1_SEQUENCE, "mmm", |
736 | 0 | keyIdentifier, |
737 | 0 | authorityCertIssuer, |
738 | 0 | authorityCertSerialNumber |
739 | 0 | ) |
740 | 0 | ) |
741 | 0 | ); |
742 | 0 | } |
743 | | |
744 | | /** |
745 | | * build extensions |
746 | | */ |
747 | | static chunk_t build_extensions(private_x509_ac_t *this) |
748 | 0 | { |
749 | 0 | return asn1_wrap(ASN1_SEQUENCE, "mc", |
750 | 0 | build_authorityKeyIdentifier(this), |
751 | 0 | ASN1_noRevAvail_ext); |
752 | 0 | } |
753 | | |
754 | | /** |
755 | | * build attributeCertificateInfo |
756 | | */ |
757 | | static chunk_t build_attr_cert_info(private_x509_ac_t *this, chunk_t sig_scheme) |
758 | 0 | { |
759 | 0 | return asn1_wrap(ASN1_SEQUENCE, "cmmcmmmm", |
760 | 0 | ASN1_INTEGER_1, |
761 | 0 | build_holder(this), |
762 | 0 | build_v2_form(this), |
763 | 0 | sig_scheme, |
764 | 0 | asn1_integer("c", this->serialNumber), |
765 | 0 | build_attr_cert_validity(this), |
766 | 0 | build_attributes(this), |
767 | 0 | build_extensions(this)); |
768 | 0 | } |
769 | | |
770 | | /** |
771 | | * build an X.509 attribute certificate |
772 | | */ |
773 | | static bool build_ac(private_x509_ac_t *this, hash_algorithm_t digest_alg) |
774 | 0 | { |
775 | 0 | chunk_t signatureValue, attributeCertificateInfo, sig_scheme; |
776 | 0 | private_key_t *key = this->signerKey; |
777 | |
|
778 | 0 | if (!this->scheme) |
779 | 0 | { |
780 | 0 | INIT(this->scheme, |
781 | 0 | .scheme = signature_scheme_from_oid( |
782 | 0 | hasher_signature_algorithm_to_oid(digest_alg, |
783 | 0 | key->get_type(key))), |
784 | 0 | ); |
785 | 0 | } |
786 | 0 | if (this->scheme->scheme == SIGN_UNKNOWN) |
787 | 0 | { |
788 | 0 | return FALSE; |
789 | 0 | } |
790 | 0 | if (!signature_params_build(this->scheme, &sig_scheme)) |
791 | 0 | { |
792 | 0 | return FALSE; |
793 | 0 | } |
794 | | |
795 | 0 | attributeCertificateInfo = build_attr_cert_info(this, sig_scheme); |
796 | 0 | if (!key->sign(key, this->scheme->scheme, this->scheme->params, |
797 | 0 | attributeCertificateInfo, &signatureValue)) |
798 | 0 | { |
799 | 0 | free(attributeCertificateInfo.ptr); |
800 | 0 | free(sig_scheme.ptr); |
801 | 0 | return FALSE; |
802 | 0 | } |
803 | 0 | this->encoding = asn1_wrap(ASN1_SEQUENCE, "mmm", |
804 | 0 | attributeCertificateInfo, |
805 | 0 | sig_scheme, |
806 | 0 | asn1_bitstring("m", signatureValue)); |
807 | 0 | return TRUE; |
808 | 0 | } |
809 | | |
810 | | METHOD(ac_t, get_serial, chunk_t, |
811 | | private_x509_ac_t *this) |
812 | 0 | { |
813 | 0 | return chunk_skip_zero(this->serialNumber); |
814 | 0 | } |
815 | | |
816 | | METHOD(ac_t, get_holderSerial, chunk_t, |
817 | | private_x509_ac_t *this) |
818 | 0 | { |
819 | 0 | if (this->holderSerial) |
820 | 0 | { |
821 | 0 | return this->holderSerial->get_encoding(this->holderSerial); |
822 | 0 | } |
823 | 0 | return chunk_empty; |
824 | 0 | } |
825 | | |
826 | | METHOD(ac_t, get_holderIssuer, identification_t*, |
827 | | private_x509_ac_t *this) |
828 | 0 | { |
829 | 0 | return this->holderIssuer; |
830 | 0 | } |
831 | | |
832 | | METHOD(ac_t, get_authKeyIdentifier, chunk_t, |
833 | | private_x509_ac_t *this) |
834 | 0 | { |
835 | 0 | return this->authKeyIdentifier; |
836 | 0 | } |
837 | | |
838 | | CALLBACK(attr_filter, bool, |
839 | | void *null, enumerator_t *orig, va_list args) |
840 | 0 | { |
841 | 0 | group_t *group; |
842 | 0 | ac_group_type_t *type; |
843 | 0 | chunk_t *out; |
844 | |
|
845 | 0 | VA_ARGS_VGET(args, type, out); |
846 | |
|
847 | 0 | while (orig->enumerate(orig, &group)) |
848 | 0 | { |
849 | 0 | if (group->type == AC_GROUP_TYPE_STRING && |
850 | 0 | !chunk_printable(group->value, NULL, 0)) |
851 | 0 | { /* skip non-printable strings */ |
852 | 0 | continue; |
853 | 0 | } |
854 | 0 | *type = group->type; |
855 | 0 | *out = group->value; |
856 | 0 | return TRUE; |
857 | 0 | } |
858 | 0 | return FALSE; |
859 | 0 | } |
860 | | |
861 | | METHOD(ac_t, create_group_enumerator, enumerator_t*, |
862 | | private_x509_ac_t *this) |
863 | 0 | { |
864 | 0 | return enumerator_create_filter( |
865 | 0 | this->groups->create_enumerator(this->groups), |
866 | 0 | attr_filter, NULL, NULL); |
867 | 0 | } |
868 | | |
869 | | METHOD(certificate_t, get_type, certificate_type_t, |
870 | | private_x509_ac_t *this) |
871 | 0 | { |
872 | 0 | return CERT_X509_AC; |
873 | 0 | } |
874 | | |
875 | | METHOD(certificate_t, get_subject, identification_t*, |
876 | | private_x509_ac_t *this) |
877 | 0 | { |
878 | 0 | if (this->entityName) |
879 | 0 | { |
880 | 0 | return this->entityName; |
881 | 0 | } |
882 | 0 | return this->holderSerial; |
883 | 0 | } |
884 | | |
885 | | METHOD(certificate_t, get_issuer, identification_t*, |
886 | | private_x509_ac_t *this) |
887 | 0 | { |
888 | 0 | return this->issuerName; |
889 | 0 | } |
890 | | |
891 | | METHOD(certificate_t, has_subject, id_match_t, |
892 | | private_x509_ac_t *this, identification_t *subject) |
893 | 0 | { |
894 | 0 | id_match_t entity = ID_MATCH_NONE, serial = ID_MATCH_NONE; |
895 | |
|
896 | 0 | if (this->entityName) |
897 | 0 | { |
898 | 0 | entity = this->entityName->matches(this->entityName, subject); |
899 | 0 | } |
900 | 0 | if (this->holderSerial) |
901 | 0 | { |
902 | 0 | serial = this->holderSerial->matches(this->holderSerial, subject); |
903 | 0 | } |
904 | 0 | return max(entity, serial); |
905 | 0 | } |
906 | | |
907 | | METHOD(certificate_t, has_issuer, id_match_t, |
908 | | private_x509_ac_t *this, identification_t *issuer) |
909 | 0 | { |
910 | 0 | if (issuer->get_type(issuer) == ID_KEY_ID && |
911 | 0 | this->authKeyIdentifier.ptr && |
912 | 0 | chunk_equals(this->authKeyIdentifier, issuer->get_encoding(issuer))) |
913 | 0 | { |
914 | 0 | return ID_MATCH_PERFECT; |
915 | 0 | } |
916 | 0 | return this->issuerName->matches(this->issuerName, issuer); |
917 | 0 | } |
918 | | |
919 | | METHOD(certificate_t, issued_by, bool, |
920 | | private_x509_ac_t *this, certificate_t *issuer, |
921 | | signature_params_t **scheme) |
922 | 0 | { |
923 | 0 | public_key_t *key; |
924 | 0 | bool valid; |
925 | 0 | x509_t *x509 = (x509_t*)issuer; |
926 | | |
927 | | /* check if issuer is an X.509 AA certificate */ |
928 | 0 | if (issuer->get_type(issuer) != CERT_X509) |
929 | 0 | { |
930 | 0 | return FALSE; |
931 | 0 | } |
932 | 0 | if (!(x509->get_flags(x509) & X509_AA)) |
933 | 0 | { |
934 | 0 | return FALSE; |
935 | 0 | } |
936 | | |
937 | | /* get the public key of the issuer */ |
938 | 0 | key = issuer->get_public_key(issuer); |
939 | | |
940 | | /* compare keyIdentifiers if available, otherwise use DNs */ |
941 | 0 | if (this->authKeyIdentifier.ptr && key) |
942 | 0 | { |
943 | 0 | chunk_t fingerprint; |
944 | |
|
945 | 0 | if (!key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fingerprint) || |
946 | 0 | !chunk_equals(fingerprint, this->authKeyIdentifier)) |
947 | 0 | { |
948 | 0 | return FALSE; |
949 | 0 | } |
950 | 0 | } |
951 | 0 | else |
952 | 0 | { |
953 | 0 | if (!this->issuerName->equals(this->issuerName, |
954 | 0 | issuer->get_subject(issuer))) |
955 | 0 | { |
956 | 0 | return FALSE; |
957 | 0 | } |
958 | 0 | } |
959 | | |
960 | 0 | if (!key) |
961 | 0 | { |
962 | 0 | return FALSE; |
963 | 0 | } |
964 | 0 | valid = key->verify(key, this->scheme->scheme, this->scheme->params, |
965 | 0 | this->certificateInfo, this->signature); |
966 | 0 | key->destroy(key); |
967 | 0 | if (valid && scheme) |
968 | 0 | { |
969 | 0 | *scheme = signature_params_clone(this->scheme); |
970 | 0 | } |
971 | 0 | return valid; |
972 | 0 | } |
973 | | |
974 | | METHOD(certificate_t, get_public_key, public_key_t*, |
975 | | private_x509_ac_t *this) |
976 | 0 | { |
977 | 0 | return NULL; |
978 | 0 | } |
979 | | |
980 | | METHOD(certificate_t, get_ref, certificate_t*, |
981 | | private_x509_ac_t *this) |
982 | 0 | { |
983 | 0 | ref_get(&this->ref); |
984 | 0 | return &this->public.interface.certificate; |
985 | 0 | } |
986 | | |
987 | | METHOD(certificate_t, get_validity, bool, |
988 | | private_x509_ac_t *this, time_t *when, time_t *not_before, time_t *not_after) |
989 | 0 | { |
990 | 0 | time_t t = when ? *when : time(NULL); |
991 | |
|
992 | 0 | if (not_before) |
993 | 0 | { |
994 | 0 | *not_before = this->notBefore; |
995 | 0 | } |
996 | 0 | if (not_after) |
997 | 0 | { |
998 | 0 | *not_after = this->notAfter; |
999 | 0 | } |
1000 | 0 | return (t >= this->notBefore && t <= this->notAfter); |
1001 | 0 | } |
1002 | | |
1003 | | METHOD(certificate_t, get_encoding, bool, |
1004 | | private_x509_ac_t *this, cred_encoding_type_t type, chunk_t *encoding) |
1005 | 0 | { |
1006 | 0 | if (type == CERT_ASN1_DER) |
1007 | 0 | { |
1008 | 0 | *encoding = chunk_clone(this->encoding); |
1009 | 0 | return TRUE; |
1010 | 0 | } |
1011 | 0 | return lib->encoding->encode(lib->encoding, type, NULL, encoding, |
1012 | 0 | CRED_PART_X509_AC_ASN1_DER, this->encoding, CRED_PART_END); |
1013 | 0 | } |
1014 | | |
1015 | | METHOD(certificate_t, equals, bool, |
1016 | | private_x509_ac_t *this, certificate_t *other) |
1017 | 0 | { |
1018 | 0 | chunk_t encoding; |
1019 | 0 | bool equal; |
1020 | |
|
1021 | 0 | if ((certificate_t*)this == other) |
1022 | 0 | { |
1023 | 0 | return TRUE; |
1024 | 0 | } |
1025 | 0 | if (other->equals == _equals) |
1026 | 0 | { /* skip allocation if we have the same implementation */ |
1027 | 0 | return chunk_equals(this->encoding, |
1028 | 0 | ((private_x509_ac_t*)other)->encoding); |
1029 | 0 | } |
1030 | 0 | if (!other->get_encoding(other, CERT_ASN1_DER, &encoding)) |
1031 | 0 | { |
1032 | 0 | return FALSE; |
1033 | 0 | } |
1034 | 0 | equal = chunk_equals(this->encoding, encoding); |
1035 | 0 | free(encoding.ptr); |
1036 | 0 | return equal; |
1037 | 0 | } |
1038 | | |
1039 | | METHOD(certificate_t, destroy, void, |
1040 | | private_x509_ac_t *this) |
1041 | 0 | { |
1042 | 0 | if (ref_put(&this->ref)) |
1043 | 0 | { |
1044 | 0 | DESTROY_IF(this->holderIssuer); |
1045 | 0 | DESTROY_IF(this->holderSerial); |
1046 | 0 | DESTROY_IF(this->entityName); |
1047 | 0 | DESTROY_IF(this->issuerName); |
1048 | 0 | DESTROY_IF(this->holderCert); |
1049 | 0 | DESTROY_IF(this->signerCert); |
1050 | 0 | DESTROY_IF(this->signerKey); |
1051 | 0 | this->groups->destroy_function(this->groups, (void*)group_destroy); |
1052 | 0 | signature_params_destroy(this->scheme); |
1053 | 0 | free(this->serialNumber.ptr); |
1054 | 0 | free(this->authKeyIdentifier.ptr); |
1055 | 0 | free(this->encoding.ptr); |
1056 | 0 | free(this); |
1057 | 0 | } |
1058 | 0 | } |
1059 | | |
1060 | | /** |
1061 | | * create an empty but initialized X.509 attribute certificate |
1062 | | */ |
1063 | | static private_x509_ac_t *create_empty(void) |
1064 | 0 | { |
1065 | 0 | private_x509_ac_t *this; |
1066 | |
|
1067 | 0 | INIT(this, |
1068 | 0 | .public = { |
1069 | 0 | .interface = { |
1070 | 0 | .certificate = { |
1071 | 0 | .get_type = _get_type, |
1072 | 0 | .get_subject = _get_subject, |
1073 | 0 | .get_issuer = _get_issuer, |
1074 | 0 | .has_subject = _has_subject, |
1075 | 0 | .has_issuer = _has_issuer, |
1076 | 0 | .issued_by = _issued_by, |
1077 | 0 | .get_public_key = _get_public_key, |
1078 | 0 | .get_validity = _get_validity, |
1079 | 0 | .get_encoding = _get_encoding, |
1080 | 0 | .equals = _equals, |
1081 | 0 | .get_ref = _get_ref, |
1082 | 0 | .destroy = _destroy, |
1083 | 0 | }, |
1084 | 0 | .get_serial = _get_serial, |
1085 | 0 | .get_holderSerial = _get_holderSerial, |
1086 | 0 | .get_holderIssuer = _get_holderIssuer, |
1087 | 0 | .get_authKeyIdentifier = _get_authKeyIdentifier, |
1088 | 0 | .create_group_enumerator = _create_group_enumerator, |
1089 | 0 | }, |
1090 | 0 | }, |
1091 | 0 | .groups = linked_list_create(), |
1092 | 0 | .ref = 1, |
1093 | 0 | ); |
1094 | |
|
1095 | 0 | return this; |
1096 | 0 | } |
1097 | | |
1098 | | /** |
1099 | | * See header. |
1100 | | */ |
1101 | | x509_ac_t *x509_ac_load(certificate_type_t type, va_list args) |
1102 | 0 | { |
1103 | 0 | chunk_t blob = chunk_empty; |
1104 | |
|
1105 | 0 | while (TRUE) |
1106 | 0 | { |
1107 | 0 | switch (va_arg(args, builder_part_t)) |
1108 | 0 | { |
1109 | 0 | case BUILD_BLOB_ASN1_DER: |
1110 | 0 | blob = va_arg(args, chunk_t); |
1111 | 0 | continue; |
1112 | 0 | case BUILD_END: |
1113 | 0 | break; |
1114 | 0 | default: |
1115 | 0 | return NULL; |
1116 | 0 | } |
1117 | 0 | break; |
1118 | 0 | } |
1119 | 0 | if (blob.ptr) |
1120 | 0 | { |
1121 | 0 | private_x509_ac_t *ac = create_empty(); |
1122 | |
|
1123 | 0 | ac->encoding = chunk_clone(blob); |
1124 | 0 | if (parse_certificate(ac)) |
1125 | 0 | { |
1126 | 0 | return &ac->public; |
1127 | 0 | } |
1128 | 0 | destroy(ac); |
1129 | 0 | } |
1130 | 0 | return NULL; |
1131 | 0 | } |
1132 | | |
1133 | | /** |
1134 | | * Add groups from a list into AC group memberships |
1135 | | */ |
1136 | | static void add_groups_from_list(private_x509_ac_t *this, linked_list_t *list) |
1137 | 0 | { |
1138 | 0 | enumerator_t *enumerator; |
1139 | 0 | group_t *group; |
1140 | 0 | char *name; |
1141 | |
|
1142 | 0 | enumerator = list->create_enumerator(list); |
1143 | 0 | while (enumerator->enumerate(enumerator, &name)) |
1144 | 0 | { |
1145 | 0 | INIT(group, |
1146 | 0 | .type = AC_GROUP_TYPE_STRING, |
1147 | 0 | .value = chunk_clone(chunk_from_str(name)), |
1148 | 0 | ); |
1149 | 0 | this->groups->insert_last(this->groups, group); |
1150 | 0 | } |
1151 | 0 | enumerator->destroy(enumerator); |
1152 | 0 | } |
1153 | | |
1154 | | /** |
1155 | | * See header. |
1156 | | */ |
1157 | | x509_ac_t *x509_ac_gen(certificate_type_t type, va_list args) |
1158 | 0 | { |
1159 | 0 | hash_algorithm_t digest_alg = HASH_SHA256; |
1160 | 0 | private_x509_ac_t *ac; |
1161 | |
|
1162 | 0 | ac = create_empty(); |
1163 | 0 | while (TRUE) |
1164 | 0 | { |
1165 | 0 | switch (va_arg(args, builder_part_t)) |
1166 | 0 | { |
1167 | 0 | case BUILD_NOT_BEFORE_TIME: |
1168 | 0 | ac->notBefore = va_arg(args, time_t); |
1169 | 0 | continue; |
1170 | 0 | case BUILD_NOT_AFTER_TIME: |
1171 | 0 | ac->notAfter = va_arg(args, time_t); |
1172 | 0 | continue; |
1173 | 0 | case BUILD_SERIAL: |
1174 | 0 | ac->serialNumber = chunk_clone(va_arg(args, chunk_t)); |
1175 | 0 | continue; |
1176 | 0 | case BUILD_AC_GROUP_STRINGS: |
1177 | 0 | add_groups_from_list(ac, va_arg(args, linked_list_t*)); |
1178 | 0 | continue; |
1179 | 0 | case BUILD_CERT: |
1180 | 0 | ac->holderCert = va_arg(args, certificate_t*); |
1181 | 0 | ac->holderCert->get_ref(ac->holderCert); |
1182 | 0 | continue; |
1183 | 0 | case BUILD_SIGNING_CERT: |
1184 | 0 | ac->signerCert = va_arg(args, certificate_t*); |
1185 | 0 | ac->signerCert->get_ref(ac->signerCert); |
1186 | 0 | continue; |
1187 | 0 | case BUILD_SIGNING_KEY: |
1188 | 0 | ac->signerKey = va_arg(args, private_key_t*); |
1189 | 0 | ac->signerKey->get_ref(ac->signerKey); |
1190 | 0 | continue; |
1191 | 0 | case BUILD_SIGNATURE_SCHEME: |
1192 | 0 | ac->scheme = va_arg(args, signature_params_t*); |
1193 | 0 | ac->scheme = signature_params_clone(ac->scheme); |
1194 | 0 | continue; |
1195 | 0 | case BUILD_DIGEST_ALG: |
1196 | 0 | digest_alg = va_arg(args, int); |
1197 | 0 | continue; |
1198 | 0 | case BUILD_END: |
1199 | 0 | break; |
1200 | 0 | default: |
1201 | 0 | destroy(ac); |
1202 | 0 | return NULL; |
1203 | 0 | } |
1204 | 0 | break; |
1205 | 0 | } |
1206 | | |
1207 | 0 | if (ac->signerKey && ac->holderCert && ac->signerCert && |
1208 | 0 | ac->holderCert->get_type(ac->holderCert) == CERT_X509 && |
1209 | 0 | ac->signerCert->get_type(ac->signerCert) == CERT_X509) |
1210 | 0 | { |
1211 | 0 | if (build_ac(ac, digest_alg)) |
1212 | 0 | { |
1213 | 0 | return &ac->public; |
1214 | 0 | } |
1215 | 0 | } |
1216 | 0 | destroy(ac); |
1217 | | return NULL; |
1218 | 0 | } |