]>
Commit | Line | Data |
---|---|---|
bdec2e4f AS |
1 | /* |
2 | * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler | |
3 | * Copyright (C) 2003 Martin Berner, Lukas Suter | |
fc12e3cd | 4 | * Copyright (C) 2002-2009 Andreas Steffen |
d73f453c | 5 | * Copyright (C) 2009 Martin Willi |
bdec2e4f | 6 | * |
fc12e3cd | 7 | * HSR Hochschule fuer Technik Rapperswil |
bdec2e4f AS |
8 | * |
9 | * This program is free software; you can redistribute it and/or modify it | |
10 | * under the terms of the GNU General Public License as published by the | |
11 | * Free Software Foundation; either version 2 of the License, or (at your | |
12 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, but | |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 | * for more details. | |
bdec2e4f AS |
18 | */ |
19 | ||
20 | #include "x509_ac.h" | |
bdec2e4f | 21 | |
e13389a7 MW |
22 | #include <time.h> |
23 | ||
bdec2e4f AS |
24 | #include <library.h> |
25 | #include <debug.h> | |
26 | #include <asn1/oid.h> | |
27 | #include <asn1/asn1.h> | |
d3d7e46b | 28 | #include <asn1/asn1_parser.h> |
bdec2e4f AS |
29 | #include <utils/identification.h> |
30 | #include <utils/linked_list.h> | |
31 | #include <credentials/certificates/x509.h> | |
fc12e3cd | 32 | #include <credentials/ietf_attributes/ietf_attributes.h> |
e24aaddd | 33 | #include <credentials/keys/private_key.h> |
bdec2e4f | 34 | |
6b6ece63 MW |
35 | extern chunk_t x509_parse_authorityKeyIdentifier(chunk_t blob, |
36 | int level0, chunk_t *authKeySerialNumber); | |
26930a8c | 37 | |
bdec2e4f AS |
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 { | |
7daf5226 | 44 | |
bdec2e4f AS |
45 | /** |
46 | * public functions | |
47 | */ | |
48 | x509_ac_t public; | |
7daf5226 | 49 | |
bdec2e4f | 50 | /** |
26930a8c | 51 | * X.509 attribute certificate encoding in ASN.1 DER format |
bdec2e4f AS |
52 | */ |
53 | chunk_t encoding; | |
7daf5226 | 54 | |
bdec2e4f AS |
55 | /** |
56 | * X.509 attribute certificate body over which signature is computed | |
57 | */ | |
58 | chunk_t certificateInfo; | |
7daf5226 | 59 | |
bdec2e4f AS |
60 | /** |
61 | * Version of the X.509 attribute certificate | |
62 | */ | |
63 | u_int version; | |
7daf5226 | 64 | |
bdec2e4f AS |
65 | /** |
66 | * Serial number of the X.509 attribute certificate | |
67 | */ | |
68 | chunk_t serialNumber; | |
7daf5226 | 69 | |
bdec2e4f AS |
70 | /** |
71 | * ID representing the issuer of the holder certificate | |
72 | */ | |
73 | identification_t *holderIssuer; | |
7daf5226 | 74 | |
bdec2e4f AS |
75 | /** |
76 | * Serial number of the holder certificate | |
77 | */ | |
78 | chunk_t holderSerial; | |
7daf5226 | 79 | |
bdec2e4f AS |
80 | /** |
81 | * ID representing the holder | |
82 | */ | |
83 | identification_t *entityName; | |
7daf5226 | 84 | |
bdec2e4f AS |
85 | /** |
86 | * ID representing the attribute certificate issuer | |
87 | */ | |
88 | identification_t *issuerName; | |
7daf5226 | 89 | |
bdec2e4f AS |
90 | /** |
91 | * Start time of certificate validity | |
92 | */ | |
93 | time_t notBefore; | |
7daf5226 | 94 | |
bdec2e4f AS |
95 | /** |
96 | * End time of certificate validity | |
97 | */ | |
98 | time_t notAfter; | |
7daf5226 | 99 | |
bdec2e4f AS |
100 | /** |
101 | * List of charging attributes | |
102 | */ | |
fc12e3cd | 103 | ietf_attributes_t *charging; |
7daf5226 | 104 | |
bdec2e4f AS |
105 | /** |
106 | * List of groub attributes | |
107 | */ | |
fc12e3cd | 108 | ietf_attributes_t *groups; |
7daf5226 | 109 | |
bdec2e4f AS |
110 | /** |
111 | * Authority Key Identifier | |
112 | */ | |
6b6ece63 | 113 | chunk_t authKeyIdentifier; |
7daf5226 | 114 | |
bdec2e4f AS |
115 | /** |
116 | * Authority Key Serial Number | |
117 | */ | |
118 | chunk_t authKeySerialNumber; | |
7daf5226 | 119 | |
bdec2e4f AS |
120 | /** |
121 | * No revocation information available | |
122 | */ | |
123 | bool noRevAvail; | |
7daf5226 | 124 | |
26930a8c AS |
125 | /** |
126 | * Signature algorithm | |
127 | */ | |
128 | int algorithm; | |
7daf5226 | 129 | |
bdec2e4f AS |
130 | /** |
131 | * Signature | |
132 | */ | |
133 | chunk_t signature; | |
7daf5226 | 134 | |
6b6ece63 MW |
135 | /** |
136 | * Holder certificate | |
137 | */ | |
6ac3a7ac | 138 | certificate_t *holderCert; |
7daf5226 | 139 | |
6b6ece63 MW |
140 | /** |
141 | * Signer certificate | |
142 | */ | |
6ac3a7ac | 143 | certificate_t *signerCert; |
7daf5226 | 144 | |
6b6ece63 MW |
145 | /** |
146 | * Signer private key; | |
147 | */ | |
6ac3a7ac | 148 | private_key_t *signerKey; |
7daf5226 | 149 | |
bdec2e4f AS |
150 | /** |
151 | * reference count | |
152 | */ | |
153 | refcount_t ref; | |
154 | }; | |
155 | ||
3b878dae | 156 | static chunk_t ASN1_noRevAvail_ext = chunk_from_chars( |
bdec2e4f AS |
157 | 0x30, 0x09, |
158 | 0x06, 0x03, | |
159 | 0x55, 0x1d, 0x38, | |
160 | 0x04, 0x02, | |
161 | 0x05, 0x00 | |
3b878dae | 162 | ); |
bdec2e4f | 163 | |
d3d7e46b AS |
164 | /** |
165 | * declaration of function implemented in x509_cert.c | |
166 | */ | |
167 | extern void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, | |
168 | linked_list_t *list); | |
169 | /** | |
170 | * parses a directoryName | |
171 | */ | |
172 | static bool parse_directoryName(chunk_t blob, int level, bool implicit, identification_t **name) | |
173 | { | |
174 | bool has_directoryName; | |
175 | linked_list_t *list = linked_list_create(); | |
176 | ||
177 | x509_parse_generalNames(blob, level, implicit, list); | |
178 | has_directoryName = list->get_count(list) > 0; | |
179 | ||
180 | if (has_directoryName) | |
181 | { | |
182 | iterator_t *iterator = list->create_iterator(list, TRUE); | |
183 | identification_t *directoryName; | |
184 | bool first = TRUE; | |
185 | ||
186 | while (iterator->iterate(iterator, (void**)&directoryName)) | |
187 | { | |
188 | if (first) | |
189 | { | |
190 | *name = directoryName; | |
191 | first = FALSE; | |
192 | } | |
193 | else | |
194 | { | |
8b0e0910 | 195 | DBG1(DBG_LIB, "more than one directory name - first selected"); |
d3d7e46b AS |
196 | directoryName->destroy(directoryName); |
197 | } | |
198 | } | |
199 | iterator->destroy(iterator); | |
200 | } | |
201 | else | |
202 | { | |
8b0e0910 | 203 | DBG1(DBG_LIB, "no directoryName found"); |
d3d7e46b AS |
204 | } |
205 | ||
206 | list->destroy(list); | |
207 | return has_directoryName; | |
208 | } | |
209 | ||
bdec2e4f AS |
210 | /** |
211 | * ASN.1 definition of roleSyntax | |
212 | */ | |
213 | static const asn1Object_t roleSyntaxObjects[] = | |
214 | { | |
460025e2 AS |
215 | { 0, "roleSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ |
216 | { 1, "roleAuthority", ASN1_CONTEXT_C_0, ASN1_OPT | | |
217 | ASN1_OBJ }, /* 1 */ | |
218 | { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ | |
219 | { 1, "roleName", ASN1_CONTEXT_C_1, ASN1_OBJ }, /* 3 */ | |
220 | { 0, "exit", ASN1_EOC, ASN1_EXIT } | |
bdec2e4f | 221 | }; |
bdec2e4f | 222 | |
d3d7e46b AS |
223 | /** |
224 | * Parses roleSyntax | |
225 | */ | |
226 | static void parse_roleSyntax(chunk_t blob, int level0) | |
227 | { | |
228 | asn1_parser_t *parser; | |
229 | chunk_t object; | |
230 | int objectID; | |
231 | ||
460025e2 | 232 | parser = asn1_parser_create(roleSyntaxObjects, blob); |
d3d7e46b AS |
233 | parser->set_top_level(parser, level0); |
234 | ||
235 | while (parser->iterate(parser, &objectID, &object)) | |
236 | { | |
237 | switch (objectID) | |
238 | { | |
239 | default: | |
240 | break; | |
241 | } | |
242 | } | |
243 | parser->destroy(parser); | |
244 | } | |
245 | ||
bdec2e4f AS |
246 | /** |
247 | * ASN.1 definition of an X509 attribute certificate | |
248 | */ | |
249 | static const asn1Object_t acObjects[] = | |
250 | { | |
251 | { 0, "AttributeCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ | |
252 | { 1, "AttributeCertificateInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ | |
253 | { 2, "version", ASN1_INTEGER, ASN1_DEF | | |
254 | ASN1_BODY }, /* 2 */ | |
255 | { 2, "holder", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */ | |
256 | { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */ | |
257 | { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ | |
258 | { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 6 */ | |
259 | { 4, "issuerUID", ASN1_BIT_STRING, ASN1_OPT | | |
260 | ASN1_BODY }, /* 7 */ | |
261 | { 4, "end opt", ASN1_EOC, ASN1_END }, /* 8 */ | |
262 | { 3, "end opt", ASN1_EOC, ASN1_END }, /* 9 */ | |
0672aa7b | 263 | { 3, "entityName", ASN1_CONTEXT_C_1, ASN1_OPT | |
bdec2e4f AS |
264 | ASN1_OBJ }, /* 10 */ |
265 | { 3, "end opt", ASN1_EOC, ASN1_END }, /* 11 */ | |
266 | { 3, "objectDigestInfo", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 12 */ | |
0672aa7b | 267 | { 4, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 13 */ |
bdec2e4f AS |
268 | { 4, "otherObjectTypeID", ASN1_OID, ASN1_OPT | |
269 | ASN1_BODY }, /* 14 */ | |
0672aa7b | 270 | { 4, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ |
bdec2e4f AS |
271 | { 4, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 16 */ |
272 | { 3, "end opt", ASN1_EOC, ASN1_END }, /* 17 */ | |
273 | { 2, "v2Form", ASN1_CONTEXT_C_0, ASN1_NONE }, /* 18 */ | |
274 | { 3, "issuerName", ASN1_SEQUENCE, ASN1_OPT | | |
275 | ASN1_OBJ }, /* 19 */ | |
276 | { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */ | |
277 | { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 21 */ | |
278 | { 4, "issuerSerial", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */ | |
279 | { 5, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 23 */ | |
b9b8a98f | 280 | { 5, "serial", ASN1_INTEGER, ASN1_BODY }, /* 24 */ |
bdec2e4f AS |
281 | { 5, "issuerUID", ASN1_BIT_STRING, ASN1_OPT | |
282 | ASN1_BODY }, /* 25 */ | |
283 | { 5, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ | |
284 | { 3, "end opt", ASN1_EOC, ASN1_END }, /* 27 */ | |
285 | { 3, "objectDigestInfo", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 28 */ | |
286 | { 4, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 29 */ | |
287 | { 5, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 30 */ | |
b9b8a98f | 288 | { 5, "otherObjectTypeID", ASN1_OID, ASN1_OPT | |
bdec2e4f AS |
289 | ASN1_BODY }, /* 31 */ |
290 | { 5, "end opt", ASN1_EOC, ASN1_END }, /* 32 */ | |
291 | { 5, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 33 */ | |
292 | { 3, "end opt", ASN1_EOC, ASN1_END }, /* 34 */ | |
293 | { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 35 */ | |
294 | { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 36 */ | |
295 | { 2, "attrCertValidityPeriod", ASN1_SEQUENCE, ASN1_NONE }, /* 37 */ | |
296 | { 3, "notBeforeTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 38 */ | |
297 | { 3, "notAfterTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 39 */ | |
298 | { 2, "attributes", ASN1_SEQUENCE, ASN1_LOOP }, /* 40 */ | |
299 | { 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 41 */ | |
300 | { 4, "type", ASN1_OID, ASN1_BODY }, /* 42 */ | |
301 | { 4, "values", ASN1_SET, ASN1_LOOP }, /* 43 */ | |
302 | { 5, "value", ASN1_EOC, ASN1_RAW }, /* 44 */ | |
303 | { 4, "end loop", ASN1_EOC, ASN1_END }, /* 45 */ | |
304 | { 2, "end loop", ASN1_EOC, ASN1_END }, /* 46 */ | |
305 | { 2, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 47 */ | |
306 | { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 48 */ | |
307 | { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 49 */ | |
308 | { 4, "critical", ASN1_BOOLEAN, ASN1_DEF | | |
309 | ASN1_BODY }, /* 50 */ | |
310 | { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 51 */ | |
311 | { 2, "end loop", ASN1_EOC, ASN1_END }, /* 52 */ | |
312 | { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 53 */ | |
460025e2 AS |
313 | { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 54 */ |
314 | { 0, "exit", ASN1_EOC, ASN1_EXIT } | |
bdec2e4f | 315 | }; |
bdec2e4f AS |
316 | #define AC_OBJ_CERTIFICATE_INFO 1 |
317 | #define AC_OBJ_VERSION 2 | |
318 | #define AC_OBJ_HOLDER_ISSUER 5 | |
319 | #define AC_OBJ_HOLDER_SERIAL 6 | |
320 | #define AC_OBJ_ENTITY_NAME 10 | |
321 | #define AC_OBJ_ISSUER_NAME 19 | |
322 | #define AC_OBJ_ISSUER 23 | |
323 | #define AC_OBJ_SIG_ALG 35 | |
324 | #define AC_OBJ_SERIAL_NUMBER 36 | |
325 | #define AC_OBJ_NOT_BEFORE 38 | |
326 | #define AC_OBJ_NOT_AFTER 39 | |
327 | #define AC_OBJ_ATTRIBUTE_TYPE 42 | |
328 | #define AC_OBJ_ATTRIBUTE_VALUE 44 | |
329 | #define AC_OBJ_EXTN_ID 49 | |
330 | #define AC_OBJ_CRITICAL 50 | |
331 | #define AC_OBJ_EXTN_VALUE 51 | |
332 | #define AC_OBJ_ALGORITHM 53 | |
333 | #define AC_OBJ_SIGNATURE 54 | |
bdec2e4f | 334 | |
26930a8c AS |
335 | /** |
336 | * Parses an X.509 attribute certificate | |
337 | */ | |
338 | static bool parse_certificate(private_x509_ac_t *this) | |
339 | { | |
d3d7e46b | 340 | asn1_parser_t *parser; |
26930a8c | 341 | chunk_t object; |
d3d7e46b AS |
342 | int objectID; |
343 | int type = OID_UNKNOWN; | |
26930a8c | 344 | int extn_oid = OID_UNKNOWN; |
d3d7e46b | 345 | int sig_alg = OID_UNKNOWN; |
c3628ebc | 346 | bool success = FALSE; |
d3d7e46b | 347 | bool critical; |
26930a8c | 348 | |
460025e2 | 349 | parser = asn1_parser_create(acObjects, this->encoding); |
26930a8c | 350 | |
d3d7e46b AS |
351 | while (parser->iterate(parser, &objectID, &object)) |
352 | { | |
353 | u_int level = parser->get_level(parser)+1; | |
26930a8c AS |
354 | |
355 | switch (objectID) | |
356 | { | |
357 | case AC_OBJ_CERTIFICATE_INFO: | |
358 | this->certificateInfo = object; | |
359 | break; | |
360 | case AC_OBJ_VERSION: | |
361 | this->version = (object.len) ? (1 + (u_int)*object.ptr) : 1; | |
8b0e0910 | 362 | DBG2(DBG_LIB, " v%d", this->version); |
26930a8c AS |
363 | if (this->version != 2) |
364 | { | |
8b0e0910 TB |
365 | DBG1(DBG_LIB, "v%d attribute certificates are not " |
366 | "supported", this->version); | |
d3d7e46b | 367 | goto end; |
26930a8c AS |
368 | } |
369 | break; | |
370 | case AC_OBJ_HOLDER_ISSUER: | |
371 | if (!parse_directoryName(object, level, FALSE, &this->holderIssuer)) | |
372 | { | |
d3d7e46b | 373 | goto end; |
26930a8c AS |
374 | } |
375 | break; | |
376 | case AC_OBJ_HOLDER_SERIAL: | |
377 | this->holderSerial = object; | |
378 | break; | |
379 | case AC_OBJ_ENTITY_NAME: | |
380 | if (!parse_directoryName(object, level, TRUE, &this->entityName)) | |
381 | { | |
d3d7e46b | 382 | goto end; |
26930a8c AS |
383 | } |
384 | break; | |
385 | case AC_OBJ_ISSUER_NAME: | |
386 | if (!parse_directoryName(object, level, FALSE, &this->issuerName)) | |
387 | { | |
d3d7e46b | 388 | goto end; |
26930a8c AS |
389 | } |
390 | break; | |
391 | case AC_OBJ_SIG_ALG: | |
d3d7e46b | 392 | sig_alg = asn1_parse_algorithmIdentifier(object, level, NULL); |
26930a8c AS |
393 | break; |
394 | case AC_OBJ_SERIAL_NUMBER: | |
9c674e72 | 395 | this->serialNumber = chunk_clone(object); |
26930a8c AS |
396 | break; |
397 | case AC_OBJ_NOT_BEFORE: | |
d3d7e46b | 398 | this->notBefore = asn1_to_time(&object, ASN1_GENERALIZEDTIME); |
26930a8c AS |
399 | break; |
400 | case AC_OBJ_NOT_AFTER: | |
d3d7e46b | 401 | this->notAfter = asn1_to_time(&object, ASN1_GENERALIZEDTIME); |
26930a8c AS |
402 | break; |
403 | case AC_OBJ_ATTRIBUTE_TYPE: | |
d3d7e46b | 404 | type = asn1_known_oid(object); |
26930a8c AS |
405 | break; |
406 | case AC_OBJ_ATTRIBUTE_VALUE: | |
d3d7e46b AS |
407 | { |
408 | switch (type) | |
26930a8c | 409 | { |
d3d7e46b | 410 | case OID_AUTHENTICATION_INFO: |
8b0e0910 | 411 | DBG2(DBG_LIB, " need to parse authenticationInfo"); |
d3d7e46b AS |
412 | break; |
413 | case OID_ACCESS_IDENTITY: | |
8b0e0910 | 414 | DBG2(DBG_LIB, " need to parse accessIdentity"); |
d3d7e46b AS |
415 | break; |
416 | case OID_CHARGING_IDENTITY: | |
8b0e0910 | 417 | DBG2(DBG_LIB, "-- > --"); |
fc12e3cd | 418 | this->charging = ietf_attributes_create_from_encoding(object); |
8b0e0910 | 419 | DBG2(DBG_LIB, "-- < --"); |
d3d7e46b AS |
420 | break; |
421 | case OID_GROUP: | |
8b0e0910 | 422 | DBG2(DBG_LIB, "-- > --"); |
fc12e3cd | 423 | this->groups = ietf_attributes_create_from_encoding(object); |
8b0e0910 | 424 | DBG2(DBG_LIB, "-- < --"); |
d3d7e46b AS |
425 | break; |
426 | case OID_ROLE: | |
427 | parse_roleSyntax(object, level); | |
428 | break; | |
429 | default: | |
430 | break; | |
26930a8c AS |
431 | } |
432 | break; | |
d3d7e46b | 433 | } |
26930a8c | 434 | case AC_OBJ_EXTN_ID: |
d3d7e46b | 435 | extn_oid = asn1_known_oid(object); |
26930a8c AS |
436 | break; |
437 | case AC_OBJ_CRITICAL: | |
438 | critical = object.len && *object.ptr; | |
8b0e0910 | 439 | DBG2(DBG_LIB, " %s",(critical)?"TRUE":"FALSE"); |
26930a8c AS |
440 | break; |
441 | case AC_OBJ_EXTN_VALUE: | |
d3d7e46b AS |
442 | { |
443 | switch (extn_oid) | |
26930a8c | 444 | { |
d3d7e46b | 445 | case OID_CRL_DISTRIBUTION_POINTS: |
8b0e0910 | 446 | DBG2(DBG_LIB, " need to parse crlDistributionPoints"); |
d3d7e46b AS |
447 | break; |
448 | case OID_AUTHORITY_KEY_ID: | |
449 | this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object, | |
6b6ece63 | 450 | level, &this->authKeySerialNumber); |
d3d7e46b AS |
451 | break; |
452 | case OID_TARGET_INFORMATION: | |
8b0e0910 | 453 | DBG2(DBG_LIB, " need to parse targetInformation"); |
d3d7e46b AS |
454 | break; |
455 | case OID_NO_REV_AVAIL: | |
456 | this->noRevAvail = TRUE; | |
457 | break; | |
458 | default: | |
26930a8c | 459 | break; |
26930a8c AS |
460 | } |
461 | break; | |
d3d7e46b | 462 | } |
26930a8c | 463 | case AC_OBJ_ALGORITHM: |
d3d7e46b AS |
464 | this->algorithm = asn1_parse_algorithmIdentifier(object, level, |
465 | NULL); | |
5298777a AS |
466 | if (this->algorithm != sig_alg) |
467 | { | |
8b0e0910 | 468 | DBG1(DBG_LIB, " signature algorithms do not agree"); |
d3d7e46b AS |
469 | success = FALSE; |
470 | goto end; | |
5298777a | 471 | } |
26930a8c AS |
472 | break; |
473 | case AC_OBJ_SIGNATURE: | |
474 | this->signature = object; | |
475 | break; | |
476 | default: | |
477 | break; | |
478 | } | |
26930a8c | 479 | } |
c3628ebc | 480 | success = parser->success(parser); |
d3d7e46b AS |
481 | |
482 | end: | |
d3d7e46b AS |
483 | parser->destroy(parser); |
484 | return success; | |
26930a8c AS |
485 | } |
486 | ||
bdec2e4f AS |
487 | /** |
488 | * build directoryName | |
489 | */ | |
490 | static chunk_t build_directoryName(asn1_t tag, chunk_t name) | |
491 | { | |
492 | return asn1_wrap(tag, "m", | |
493 | asn1_simple_object(ASN1_CONTEXT_C_4, name)); | |
494 | } | |
495 | ||
496 | /** | |
497 | * build holder | |
498 | */ | |
499 | static chunk_t build_holder(private_x509_ac_t *this) | |
500 | { | |
6ac3a7ac AS |
501 | x509_t* x509 = (x509_t*)this->holderCert; |
502 | identification_t *issuer = this->holderCert->get_issuer(this->holderCert); | |
503 | identification_t *subject = this->holderCert->get_subject(this->holderCert); | |
bdec2e4f AS |
504 | |
505 | return asn1_wrap(ASN1_SEQUENCE, "mm", | |
506 | asn1_wrap(ASN1_CONTEXT_C_0, "mm", | |
507 | build_directoryName(ASN1_SEQUENCE, issuer->get_encoding(issuer)), | |
508 | asn1_simple_object(ASN1_INTEGER, x509->get_serial(x509)) | |
509 | ), | |
510 | build_directoryName(ASN1_CONTEXT_C_1, subject->get_encoding(subject))); | |
511 | } | |
512 | ||
513 | /** | |
514 | * build v2Form | |
515 | */ | |
516 | static chunk_t build_v2_form(private_x509_ac_t *this) | |
517 | { | |
6ac3a7ac | 518 | identification_t *subject = this->signerCert->get_subject(this->signerCert); |
bdec2e4f AS |
519 | |
520 | return asn1_wrap(ASN1_CONTEXT_C_0, "m", | |
521 | build_directoryName(ASN1_SEQUENCE, subject->get_encoding(subject))); | |
522 | } | |
523 | ||
524 | /** | |
525 | * build attrCertValidityPeriod | |
526 | */ | |
527 | static chunk_t build_attr_cert_validity(private_x509_ac_t *this) | |
528 | { | |
529 | return asn1_wrap(ASN1_SEQUENCE, "mm", | |
d3d7e46b AS |
530 | asn1_from_time(&this->notBefore, ASN1_GENERALIZEDTIME), |
531 | asn1_from_time(&this->notAfter, ASN1_GENERALIZEDTIME)); | |
bdec2e4f AS |
532 | } |
533 | ||
534 | ||
535 | /** | |
536 | * build attribute type | |
537 | */ | |
70e81857 | 538 | static chunk_t build_attribute_type(int type, chunk_t content) |
bdec2e4f | 539 | { |
70e81857 AS |
540 | return asn1_wrap(ASN1_SEQUENCE, "mm", |
541 | asn1_build_known_oid(type), | |
bdec2e4f AS |
542 | asn1_wrap(ASN1_SET, "m", content)); |
543 | } | |
544 | ||
545 | /** | |
546 | * build attributes | |
547 | */ | |
548 | static chunk_t build_attributes(private_x509_ac_t *this) | |
549 | { | |
550 | return asn1_wrap(ASN1_SEQUENCE, "m", | |
fc12e3cd | 551 | build_attribute_type(OID_GROUP, this->groups->get_encoding(this->groups))); |
bdec2e4f AS |
552 | } |
553 | ||
554 | /** | |
555 | * build authorityKeyIdentifier | |
556 | */ | |
557 | static chunk_t build_authorityKeyIdentifier(private_x509_ac_t *this) | |
558 | { | |
6b6ece63 | 559 | chunk_t keyIdentifier = chunk_empty; |
bdec2e4f AS |
560 | chunk_t authorityCertIssuer; |
561 | chunk_t authorityCertSerialNumber; | |
6b6ece63 MW |
562 | identification_t *issuer; |
563 | public_key_t *public; | |
564 | x509_t *x509; | |
7daf5226 | 565 | |
6b6ece63 MW |
566 | x509 = (x509_t*)this->signerCert; |
567 | issuer = this->signerCert->get_issuer(this->signerCert); | |
568 | public = this->signerCert->get_public_key(this->signerCert); | |
bdec2e4f AS |
569 | if (public) |
570 | { | |
da9724e6 | 571 | if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &keyIdentifier)) |
6b6ece63 MW |
572 | { |
573 | this->authKeyIdentifier = chunk_clone(keyIdentifier); | |
574 | } | |
bdec2e4f | 575 | public->destroy(public); |
bdec2e4f | 576 | } |
bdec2e4f | 577 | authorityCertIssuer = build_directoryName(ASN1_CONTEXT_C_1, |
6b6ece63 | 578 | issuer->get_encoding(issuer)); |
bdec2e4f | 579 | authorityCertSerialNumber = asn1_simple_object(ASN1_CONTEXT_S_2, |
6b6ece63 | 580 | x509->get_serial(x509)); |
70e81857 AS |
581 | return asn1_wrap(ASN1_SEQUENCE, "mm", |
582 | asn1_build_known_oid(OID_AUTHORITY_KEY_ID), | |
bdec2e4f | 583 | asn1_wrap(ASN1_OCTET_STRING, "m", |
93da2684 | 584 | asn1_wrap(ASN1_SEQUENCE, "cmm", |
bdec2e4f AS |
585 | keyIdentifier, |
586 | authorityCertIssuer, | |
587 | authorityCertSerialNumber | |
588 | ) | |
589 | ) | |
590 | ); | |
591 | } | |
592 | ||
593 | /** | |
594 | * build extensions | |
595 | */ | |
596 | static chunk_t build_extensions(private_x509_ac_t *this) | |
597 | { | |
598 | return asn1_wrap(ASN1_SEQUENCE, "mc", | |
104c96a6 | 599 | build_authorityKeyIdentifier(this), |
bdec2e4f AS |
600 | ASN1_noRevAvail_ext); |
601 | } | |
602 | ||
603 | /** | |
604 | * build attributeCertificateInfo | |
605 | */ | |
606 | static chunk_t build_attr_cert_info(private_x509_ac_t *this) | |
607 | { | |
eb73685d | 608 | return asn1_wrap(ASN1_SEQUENCE, "cmmmmmmm", |
bdec2e4f AS |
609 | ASN1_INTEGER_1, |
610 | build_holder(this), | |
611 | build_v2_form(this), | |
612 | asn1_algorithmIdentifier(OID_SHA1_WITH_RSA), | |
613 | asn1_simple_object(ASN1_INTEGER, this->serialNumber), | |
614 | build_attr_cert_validity(this), | |
615 | build_attributes(this), | |
616 | build_extensions(this)); | |
617 | } | |
618 | ||
619 | ||
620 | /** | |
621 | * build an X.509 attribute certificate | |
622 | */ | |
623 | static chunk_t build_ac(private_x509_ac_t *this) | |
624 | { | |
625 | chunk_t signatureValue; | |
323f9f99 | 626 | chunk_t attributeCertificateInfo; |
104c96a6 | 627 | |
104c96a6 AS |
628 | attributeCertificateInfo = build_attr_cert_info(this); |
629 | ||
630 | this->signerKey->sign(this->signerKey, SIGN_RSA_EMSA_PKCS1_SHA1, | |
631 | attributeCertificateInfo, &signatureValue); | |
632 | ||
eb73685d | 633 | return asn1_wrap(ASN1_SEQUENCE, "mmm", |
bdec2e4f AS |
634 | attributeCertificateInfo, |
635 | asn1_algorithmIdentifier(OID_SHA1_WITH_RSA), | |
636 | asn1_bitstring("m", signatureValue)); | |
637 | } | |
638 | ||
0672aa7b AS |
639 | /** |
640 | * Implementation of ac_t.get_serial. | |
641 | */ | |
642 | static chunk_t get_serial(private_x509_ac_t *this) | |
643 | { | |
644 | return this->serialNumber; | |
645 | } | |
646 | ||
647 | /** | |
648 | * Implementation of ac_t.get_holderSerial. | |
649 | */ | |
650 | static chunk_t get_holderSerial(private_x509_ac_t *this) | |
651 | { | |
652 | return this->holderSerial; | |
653 | } | |
654 | ||
655 | /** | |
656 | * Implementation of ac_t.get_holderIssuer. | |
657 | */ | |
658 | static identification_t* get_holderIssuer(private_x509_ac_t *this) | |
659 | { | |
660 | return this->holderIssuer; | |
661 | } | |
662 | ||
663 | /** | |
664 | * Implementation of ac_t.get_authKeyIdentifier. | |
665 | */ | |
6b6ece63 | 666 | static chunk_t get_authKeyIdentifier(private_x509_ac_t *this) |
0672aa7b AS |
667 | { |
668 | return this->authKeyIdentifier; | |
669 | } | |
670 | ||
fc12e3cd AS |
671 | /** |
672 | * Implementation of certificate_t.get_groups. | |
673 | */ | |
674 | static ietf_attributes_t* get_groups(private_x509_ac_t *this) | |
675 | { | |
676 | return this->groups ? this->groups->get_ref(this->groups) : NULL; | |
677 | } | |
678 | ||
bdec2e4f AS |
679 | /** |
680 | * Implementation of certificate_t.get_type | |
681 | */ | |
682 | static certificate_type_t get_type(private_x509_ac_t *this) | |
683 | { | |
684 | return CERT_X509_AC; | |
685 | } | |
686 | ||
687 | /** | |
688 | * Implementation of certificate_t.get_subject | |
689 | */ | |
690 | static identification_t* get_subject(private_x509_ac_t *this) | |
691 | { | |
692 | return this->entityName; | |
693 | } | |
694 | ||
695 | /** | |
696 | * Implementation of certificate_t.get_issuer | |
697 | */ | |
698 | static identification_t* get_issuer(private_x509_ac_t *this) | |
699 | { | |
700 | return this->issuerName; | |
701 | } | |
702 | ||
703 | /** | |
704 | * Implementation of certificate_t.has_subject. | |
705 | */ | |
706 | static id_match_t has_subject(private_x509_ac_t *this, identification_t *subject) | |
707 | { | |
6b6ece63 | 708 | return ID_MATCH_NONE; |
bdec2e4f AS |
709 | } |
710 | ||
711 | /** | |
712 | * Implementation of certificate_t.has_issuer. | |
713 | */ | |
714 | static id_match_t has_issuer(private_x509_ac_t *this, identification_t *issuer) | |
715 | { | |
6b6ece63 MW |
716 | if (issuer->get_type(issuer) == ID_KEY_ID && this->authKeyIdentifier.ptr && |
717 | chunk_equals(this->authKeyIdentifier, issuer->get_encoding(issuer))) | |
bdec2e4f | 718 | { |
6b6ece63 | 719 | return ID_MATCH_PERFECT; |
bdec2e4f | 720 | } |
6b6ece63 | 721 | return this->issuerName->matches(this->issuerName, issuer); |
bdec2e4f AS |
722 | } |
723 | ||
724 | /** | |
725 | * Implementation of certificate_t.issued_by | |
726 | */ | |
7b88a983 | 727 | static bool issued_by(private_x509_ac_t *this, certificate_t *issuer) |
bdec2e4f AS |
728 | { |
729 | public_key_t *key; | |
730 | signature_scheme_t scheme; | |
731 | bool valid; | |
732 | x509_t *x509 = (x509_t*)issuer; | |
7daf5226 | 733 | |
bdec2e4f AS |
734 | /* check if issuer is an X.509 AA certificate */ |
735 | if (issuer->get_type(issuer) != CERT_X509) | |
736 | { | |
737 | return FALSE; | |
738 | } | |
739 | if (!(x509->get_flags(x509) & X509_AA)) | |
740 | { | |
741 | return FALSE; | |
742 | } | |
7daf5226 | 743 | |
bdec2e4f AS |
744 | /* get the public key of the issuer */ |
745 | key = issuer->get_public_key(issuer); | |
7daf5226 | 746 | |
bdec2e4f | 747 | /* compare keyIdentifiers if available, otherwise use DNs */ |
6b6ece63 | 748 | if (this->authKeyIdentifier.ptr && key) |
bdec2e4f | 749 | { |
6b6ece63 | 750 | chunk_t fingerprint; |
7daf5226 | 751 | |
da9724e6 | 752 | if (!key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fingerprint) || |
6b6ece63 | 753 | !chunk_equals(fingerprint, this->authKeyIdentifier)) |
bdec2e4f AS |
754 | { |
755 | return FALSE; | |
756 | } | |
757 | } | |
7daf5226 | 758 | else |
bdec2e4f | 759 | { |
6b6ece63 MW |
760 | if (!this->issuerName->equals(this->issuerName, |
761 | issuer->get_subject(issuer))) | |
bdec2e4f AS |
762 | { |
763 | return FALSE; | |
764 | } | |
765 | } | |
7daf5226 | 766 | |
f3e87f59 AS |
767 | /* determine signature scheme */ |
768 | scheme = signature_scheme_from_oid(this->algorithm); | |
7daf5226 | 769 | |
f3e87f59 | 770 | if (scheme == SIGN_UNKNOWN || key == NULL) |
bdec2e4f AS |
771 | { |
772 | return FALSE; | |
773 | } | |
774 | valid = key->verify(key, scheme, this->certificateInfo, this->signature); | |
775 | key->destroy(key); | |
776 | return valid; | |
777 | } | |
778 | ||
779 | /** | |
780 | * Implementation of certificate_t.get_public_key. | |
781 | */ | |
782 | static public_key_t* get_public_key(private_x509_ac_t *this) | |
783 | { | |
784 | return NULL; | |
785 | } | |
786 | ||
787 | /** | |
788 | * Implementation of certificate_t.get_ref. | |
789 | */ | |
790 | static private_x509_ac_t* get_ref(private_x509_ac_t *this) | |
791 | { | |
792 | ref_get(&this->ref); | |
793 | return this; | |
794 | } | |
795 | ||
796 | /** | |
797 | * Implementation of certificate_t.get_validity. | |
798 | */ | |
799 | static bool get_validity(private_x509_ac_t *this, time_t *when, | |
800 | time_t *not_before, time_t *not_after) | |
801 | { | |
cf85e131 | 802 | time_t t = when ? *when : time(NULL); |
7daf5226 | 803 | |
bdec2e4f AS |
804 | if (not_before) |
805 | { | |
806 | *not_before = this->notBefore; | |
807 | } | |
808 | if (not_after) | |
809 | { | |
810 | *not_after = this->notAfter; | |
811 | } | |
cf85e131 | 812 | return (t >= this->notBefore && t <= this->notAfter); |
bdec2e4f AS |
813 | } |
814 | ||
bdec2e4f AS |
815 | /** |
816 | * Implementation of certificate_t.get_encoding. | |
817 | */ | |
0406eeaa MW |
818 | static bool get_encoding(private_x509_ac_t *this, cred_encoding_type_t type, |
819 | chunk_t *encoding) | |
bdec2e4f | 820 | { |
0406eeaa MW |
821 | if (type == CERT_ASN1_DER) |
822 | { | |
823 | *encoding = chunk_clone(this->encoding); | |
824 | return TRUE; | |
825 | } | |
826 | return lib->encoding->encode(lib->encoding, type, NULL, encoding, | |
827 | CRED_PART_X509_AC_ASN1_DER, this->encoding, CRED_PART_END); | |
bdec2e4f AS |
828 | } |
829 | ||
830 | /** | |
831 | * Implementation of certificate_t.equals. | |
832 | */ | |
833 | static bool equals(private_x509_ac_t *this, certificate_t *other) | |
834 | { | |
b5dbcc62 MW |
835 | chunk_t encoding; |
836 | bool equal; | |
7daf5226 | 837 | |
bdec2e4f AS |
838 | if ((certificate_t*)this == other) |
839 | { | |
840 | return TRUE; | |
841 | } | |
842 | if (other->equals == (void*)equals) | |
b5dbcc62 | 843 | { /* skip allocation if we have the same implementation */ |
7daf5226 | 844 | return chunk_equals(this->encoding, ((private_x509_ac_t*)other)->encoding); |
bdec2e4f | 845 | } |
0406eeaa MW |
846 | if (!other->get_encoding(other, CERT_ASN1_DER, &encoding)) |
847 | { | |
848 | return FALSE; | |
849 | } | |
b5dbcc62 MW |
850 | equal = chunk_equals(this->encoding, encoding); |
851 | free(encoding.ptr); | |
852 | return equal; | |
bdec2e4f AS |
853 | } |
854 | ||
855 | /** | |
856 | * Implementation of x509_ac_t.destroy | |
857 | */ | |
858 | static void destroy(private_x509_ac_t *this) | |
859 | { | |
860 | if (ref_put(&this->ref)) | |
861 | { | |
862 | DESTROY_IF(this->holderIssuer); | |
863 | DESTROY_IF(this->entityName); | |
864 | DESTROY_IF(this->issuerName); | |
63cb8a7f AS |
865 | DESTROY_IF(this->holderCert); |
866 | DESTROY_IF(this->signerCert); | |
867 | DESTROY_IF(this->signerKey); | |
fc12e3cd AS |
868 | DESTROY_IF(this->charging); |
869 | DESTROY_IF(this->groups); | |
9c674e72 | 870 | free(this->serialNumber.ptr); |
6b6ece63 | 871 | free(this->authKeyIdentifier.ptr); |
bdec2e4f AS |
872 | free(this->encoding.ptr); |
873 | free(this); | |
874 | } | |
875 | } | |
876 | ||
877 | /** | |
878 | * create an empty but initialized X.509 attribute certificate | |
879 | */ | |
26930a8c | 880 | static private_x509_ac_t *create_empty(void) |
bdec2e4f AS |
881 | { |
882 | private_x509_ac_t *this = malloc_thing(private_x509_ac_t); | |
7daf5226 | 883 | |
bdec2e4f | 884 | /* public functions */ |
0672aa7b AS |
885 | this->public.interface.get_serial = (chunk_t (*)(ac_t*))get_serial; |
886 | this->public.interface.get_holderSerial = (chunk_t (*)(ac_t*))get_holderSerial; | |
887 | this->public.interface.get_holderIssuer = (identification_t* (*)(ac_t*))get_holderIssuer; | |
fc12e3cd AS |
888 | this->public.interface.get_authKeyIdentifier = (chunk_t (*)(ac_t*))get_authKeyIdentifier; |
889 | this->public.interface.get_groups = (ietf_attributes_t* (*)(ac_t*))get_groups; | |
bdec2e4f AS |
890 | this->public.interface.certificate.get_type = (certificate_type_t (*)(certificate_t *this))get_type; |
891 | this->public.interface.certificate.get_subject = (identification_t* (*)(certificate_t *this))get_subject; | |
892 | this->public.interface.certificate.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer; | |
893 | this->public.interface.certificate.has_subject = (id_match_t(*)(certificate_t*, identification_t *subject))has_subject; | |
894 | this->public.interface.certificate.has_issuer = (id_match_t(*)(certificate_t*, identification_t *issuer))has_issuer; | |
7b88a983 | 895 | this->public.interface.certificate.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer))issued_by; |
bdec2e4f AS |
896 | this->public.interface.certificate.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key; |
897 | this->public.interface.certificate.get_validity = (bool(*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity; | |
0406eeaa | 898 | this->public.interface.certificate.get_encoding = (bool(*)(certificate_t*,cred_encoding_type_t,chunk_t*))get_encoding; |
bdec2e4f AS |
899 | this->public.interface.certificate.equals = (bool(*)(certificate_t*, certificate_t *other))equals; |
900 | this->public.interface.certificate.get_ref = (certificate_t* (*)(certificate_t *this))get_ref; | |
901 | this->public.interface.certificate.destroy = (void (*)(certificate_t *this))destroy; | |
902 | ||
903 | /* initialize */ | |
93da2684 | 904 | this->encoding = chunk_empty; |
9c674e72 | 905 | this->serialNumber = chunk_empty; |
0672aa7b | 906 | this->holderSerial = chunk_empty; |
6b6ece63 | 907 | this->authKeyIdentifier = chunk_empty; |
bdec2e4f AS |
908 | this->holderIssuer = NULL; |
909 | this->entityName = NULL; | |
910 | this->issuerName = NULL; | |
6ac3a7ac AS |
911 | this->holderCert = NULL; |
912 | this->signerCert = NULL; | |
913 | this->signerKey = NULL; | |
fc12e3cd AS |
914 | this->charging = NULL; |
915 | this->groups = NULL; | |
104c96a6 | 916 | this->ref = 1; |
bdec2e4f AS |
917 | |
918 | return this; | |
919 | } | |
920 | ||
26930a8c | 921 | /** |
d73f453c | 922 | * See header. |
26930a8c | 923 | */ |
d73f453c | 924 | x509_ac_t *x509_ac_load(certificate_type_t type, va_list args) |
26930a8c | 925 | { |
d73f453c | 926 | chunk_t blob = chunk_empty; |
26930a8c | 927 | |
d73f453c | 928 | while (TRUE) |
26930a8c | 929 | { |
d73f453c MW |
930 | switch (va_arg(args, builder_part_t)) |
931 | { | |
932 | case BUILD_BLOB_ASN1_DER: | |
933 | blob = va_arg(args, chunk_t); | |
934 | continue; | |
935 | case BUILD_END: | |
936 | break; | |
937 | default: | |
938 | return NULL; | |
939 | } | |
940 | break; | |
26930a8c | 941 | } |
d73f453c | 942 | if (blob.ptr) |
bdec2e4f | 943 | { |
d73f453c MW |
944 | private_x509_ac_t *ac = create_empty(); |
945 | ||
946 | ac->encoding = chunk_clone(blob); | |
947 | if (parse_certificate(ac)) | |
26930a8c | 948 | { |
d73f453c | 949 | return &ac->public; |
26930a8c AS |
950 | } |
951 | destroy(ac); | |
a852928a | 952 | } |
d73f453c | 953 | return NULL; |
bdec2e4f AS |
954 | } |
955 | ||
956 | /** | |
d73f453c | 957 | * See header. |
bdec2e4f | 958 | */ |
d73f453c | 959 | x509_ac_t *x509_ac_gen(certificate_type_t type, va_list args) |
bdec2e4f | 960 | { |
d73f453c | 961 | private_x509_ac_t *ac; |
6ac3a7ac | 962 | |
d73f453c MW |
963 | ac = create_empty(); |
964 | while (TRUE) | |
bdec2e4f | 965 | { |
d73f453c MW |
966 | switch (va_arg(args, builder_part_t)) |
967 | { | |
968 | case BUILD_NOT_BEFORE_TIME: | |
969 | ac->notBefore = va_arg(args, time_t); | |
970 | continue; | |
971 | case BUILD_NOT_AFTER_TIME: | |
972 | ac->notAfter = va_arg(args, time_t); | |
973 | continue; | |
974 | case BUILD_SERIAL: | |
975 | ac->serialNumber = chunk_clone(va_arg(args, chunk_t)); | |
976 | continue; | |
977 | case BUILD_IETF_GROUP_ATTR: | |
fc12e3cd | 978 | ac->groups = ietf_attributes_create_from_string(va_arg(args, char*)); |
d73f453c MW |
979 | continue; |
980 | case BUILD_CERT: | |
981 | ac->holderCert = va_arg(args, certificate_t*); | |
982 | ac->holderCert->get_ref(ac->holderCert); | |
983 | continue; | |
984 | case BUILD_SIGNING_CERT: | |
985 | ac->signerCert = va_arg(args, certificate_t*); | |
986 | ac->signerCert->get_ref(ac->signerCert); | |
987 | continue; | |
988 | case BUILD_SIGNING_KEY: | |
989 | ac->signerKey = va_arg(args, private_key_t*); | |
990 | ac->signerKey->get_ref(ac->signerKey); | |
991 | continue; | |
992 | case BUILD_END: | |
993 | break; | |
994 | default: | |
995 | destroy(ac); | |
996 | return NULL; | |
997 | } | |
998 | break; | |
bdec2e4f | 999 | } |
bdec2e4f | 1000 | |
d73f453c MW |
1001 | if (ac->signerKey && ac->holderCert && ac->signerCert && |
1002 | ac->holderCert->get_type(ac->holderCert) == CERT_X509 && | |
1003 | ac->signerCert->get_type(ac->signerCert) == CERT_X509) | |
bdec2e4f | 1004 | { |
d73f453c MW |
1005 | ac->encoding = build_ac(ac); |
1006 | return &ac->public; | |
bdec2e4f | 1007 | } |
d73f453c MW |
1008 | destroy(ac); |
1009 | return NULL; | |
bdec2e4f AS |
1010 | } |
1011 |