Migrated x509_pkcs10 to INIT/METHOD macros
[strongswan.git] / src / libstrongswan / plugins / x509 / x509_pkcs10.c
1 /*
2 * Copyright (C) 2005 Jan Hutter, Martin Willi
3 * Copyright (C) 2009 Andreas Steffen
4 *
5 * HSR Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include "x509_pkcs10.h"
19
20 #include <library.h>
21 #include <debug.h>
22 #include <asn1/oid.h>
23 #include <asn1/asn1.h>
24 #include <asn1/asn1_parser.h>
25 #include <credentials/keys/private_key.h>
26 #include <utils/linked_list.h>
27 #include <utils/identification.h>
28
29 typedef struct private_x509_pkcs10_t private_x509_pkcs10_t;
30
31 /**
32 * Private data of a x509_pkcs10_t object.
33 */
34 struct private_x509_pkcs10_t {
35 /**
36 * Public interface for this certificate.
37 */
38 x509_pkcs10_t public;
39
40 /**
41 * PKCS#10 certificate request encoding in ASN.1 DER format
42 */
43 chunk_t encoding;
44
45 /**
46 * PKCS#10 request body over which signature is computed
47 */
48 chunk_t certificationRequestInfo;
49
50 /**
51 * Version of the PKCS#10 certificate request
52 */
53 u_int version;
54
55 /**
56 * ID representing the certificate subject
57 */
58 identification_t *subject;
59
60 /**
61 * List of subjectAltNames as identification_t
62 */
63 linked_list_t *subjectAltNames;
64
65 /**
66 * certificate's embedded public key
67 */
68 public_key_t *public_key;
69
70 /**
71 * challenge password
72 */
73 chunk_t challengePassword;
74
75 /**
76 * Signature algorithm
77 */
78 int algorithm;
79
80 /**
81 * Signature
82 */
83 chunk_t signature;
84
85 /**
86 * Is the certificate request self-signed?
87 */
88 bool self_signed;
89
90 /**
91 * Certificate request parsed from blob/file?
92 */
93 bool parsed;
94
95 /**
96 * reference count
97 */
98 refcount_t ref;
99 };
100
101 /**
102 * Imported from x509_cert.c
103 */
104 extern void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list);
105 extern chunk_t x509_build_subjectAltNames(linked_list_t *list);
106
107 METHOD(certificate_t, get_type, certificate_type_t,
108 private_x509_pkcs10_t *this)
109 {
110 return CERT_PKCS10_REQUEST;
111 }
112
113 METHOD(certificate_t, get_subject, identification_t*,
114 private_x509_pkcs10_t *this)
115 {
116 return this->subject;
117 }
118
119 METHOD(certificate_t, has_subject, id_match_t,
120 private_x509_pkcs10_t *this, identification_t *subject)
121 {
122 return this->subject->matches(this->subject, subject);
123 }
124
125 METHOD(certificate_t, issued_by, bool,
126 private_x509_pkcs10_t *this, certificate_t *issuer)
127 {
128 public_key_t *key;
129 signature_scheme_t scheme;
130
131 if (&this->public.interface.interface != issuer)
132 {
133 return FALSE;
134 }
135 if (this->self_signed)
136 {
137 return TRUE;
138 }
139
140 /* determine signature scheme */
141 scheme = signature_scheme_from_oid(this->algorithm);
142 if (scheme == SIGN_UNKNOWN)
143 {
144 return FALSE;
145 }
146
147 /* get the public key contained in the certificate request */
148 key = this->public_key;
149 if (!key)
150 {
151 return FALSE;
152 }
153 return key->verify(key, scheme, this->certificationRequestInfo,
154 this->signature);
155 }
156
157 METHOD(certificate_t, get_public_key, public_key_t*,
158 private_x509_pkcs10_t *this)
159 {
160 this->public_key->get_ref(this->public_key);
161 return this->public_key;
162 }
163
164 METHOD(certificate_t, get_validity, bool,
165 private_x509_pkcs10_t *this, time_t *when, time_t *not_before,
166 time_t *not_after)
167 {
168 if (not_before)
169 {
170 *not_before = 0;
171 }
172 if (not_after)
173 {
174 *not_after = ~0;
175 }
176 return TRUE;
177 }
178
179 METHOD(certificate_t, get_encoding, bool,
180 private_x509_pkcs10_t *this, cred_encoding_type_t type, chunk_t *encoding)
181 {
182 if (type == CERT_ASN1_DER)
183 {
184 *encoding = chunk_clone(this->encoding);
185 return TRUE;
186 }
187 return lib->encoding->encode(lib->encoding, type, NULL, encoding,
188 CRED_PART_PKCS10_ASN1_DER, this->encoding, CRED_PART_END);
189 }
190
191 METHOD(certificate_t, equals, bool,
192 private_x509_pkcs10_t *this, certificate_t *other)
193 {
194 chunk_t encoding;
195 bool equal;
196
197 if (this == (private_x509_pkcs10_t*)other)
198 {
199 return TRUE;
200 }
201 if (other->get_type(other) != CERT_PKCS10_REQUEST)
202 {
203 return FALSE;
204 }
205 if (other->equals == (void*)equals)
206 { /* skip allocation if we have the same implementation */
207 return chunk_equals(this->encoding, ((private_x509_pkcs10_t*)other)->encoding);
208 }
209 if (!other->get_encoding(other, CERT_ASN1_DER, &encoding))
210 {
211 return FALSE;
212 }
213 equal = chunk_equals(this->encoding, encoding);
214 free(encoding.ptr);
215 return equal;
216 }
217
218 METHOD(certificate_t, get_ref, certificate_t*,
219 private_x509_pkcs10_t *this)
220 {
221 ref_get(&this->ref);
222 return &this->public.interface.interface;
223 }
224
225 METHOD(pkcs10_t, get_challengePassword, chunk_t,
226 private_x509_pkcs10_t *this)
227 {
228 return this->challengePassword;
229 }
230
231 METHOD(pkcs10_t, create_subjectAltName_enumerator, enumerator_t*,
232 private_x509_pkcs10_t *this)
233 {
234 return this->subjectAltNames->create_enumerator(this->subjectAltNames);
235 }
236
237 /**
238 * ASN.1 definition of a PKCS#10 extension request
239 */
240 static const asn1Object_t extensionRequestObjects[] = {
241 { 0, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
242 { 1, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
243 { 2, "extnID", ASN1_OID, ASN1_BODY }, /* 2 */
244 { 2, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 3 */
245 { 2, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */
246 { 1, "end loop", ASN1_EOC, ASN1_END }, /* 5 */
247 { 0, "exit", ASN1_EOC, ASN1_EXIT }
248 };
249 #define PKCS10_EXTN_ID 2
250 #define PKCS10_EXTN_CRITICAL 3
251 #define PKCS10_EXTN_VALUE 4
252
253 /**
254 * Parses a PKCS#10 extension request
255 */
256 static bool parse_extension_request(private_x509_pkcs10_t *this, chunk_t blob, int level0)
257 {
258 asn1_parser_t *parser;
259 chunk_t object;
260 int objectID;
261 int extn_oid = OID_UNKNOWN;
262 bool success = FALSE;
263 bool critical;
264
265 parser = asn1_parser_create(extensionRequestObjects, blob);
266 parser->set_top_level(parser, level0);
267
268 while (parser->iterate(parser, &objectID, &object))
269 {
270 u_int level = parser->get_level(parser)+1;
271
272 switch (objectID)
273 {
274 case PKCS10_EXTN_ID:
275 extn_oid = asn1_known_oid(object);
276 break;
277 case PKCS10_EXTN_CRITICAL:
278 critical = object.len && *object.ptr;
279 DBG2(DBG_LIB, " %s", critical ? "TRUE" : "FALSE");
280 break;
281 case PKCS10_EXTN_VALUE:
282 {
283 switch (extn_oid)
284 {
285 case OID_SUBJECT_ALT_NAME:
286 x509_parse_generalNames(object, level, FALSE,
287 this->subjectAltNames);
288 break;
289 default:
290 break;
291 }
292 break;
293 }
294 default:
295 break;
296 }
297 }
298 success = parser->success(parser);
299 parser->destroy(parser);
300 return success;
301 }
302
303 /**
304 * Parses a PKCS#10 challenge password
305 */
306 static bool parse_challengePassword(private_x509_pkcs10_t *this, chunk_t blob, int level)
307 {
308 char tag;
309
310 if (blob.len < 2)
311 {
312 DBG1(DBG_LIB, "L%d - challengePassword: ASN.1 object smaller "
313 "than 2 octets", level);
314 return FALSE;
315 }
316 tag = *blob.ptr;
317 if (tag < ASN1_UTF8STRING || tag > ASN1_IA5STRING)
318 {
319 DBG1(DBG_LIB, "L%d - challengePassword: ASN.1 object is not "
320 "a character string", level);
321 return FALSE;
322 }
323 if (asn1_length(&blob) == ASN1_INVALID_LENGTH)
324 {
325 DBG1(DBG_LIB, "L%d - challengePassword: ASN.1 object has an "
326 "invalid length", level);
327 return FALSE;
328 }
329 DBG2(DBG_LIB, "L%d - challengePassword:", level);
330 DBG4(DBG_LIB, " '%.*s'", blob.len, blob.ptr);
331 return TRUE;
332 }
333
334 /**
335 * ASN.1 definition of a PKCS#10 certificate request
336 */
337 static const asn1Object_t certificationRequestObjects[] = {
338 { 0, "certificationRequest", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
339 { 1, "certificationRequestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
340 { 2, "version", ASN1_INTEGER, ASN1_BODY }, /* 2 */
341 { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 3 */
342 { 2, "subjectPublicKeyInfo", ASN1_SEQUENCE, ASN1_RAW }, /* 4 */
343 { 2, "attributes", ASN1_CONTEXT_C_0, ASN1_LOOP }, /* 5 */
344 { 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 6 */
345 { 4, "type", ASN1_OID, ASN1_BODY }, /* 7 */
346 { 4, "values", ASN1_SET, ASN1_LOOP }, /* 8 */
347 { 5, "value", ASN1_EOC, ASN1_RAW }, /* 9 */
348 { 4, "end loop", ASN1_EOC, ASN1_END }, /* 10 */
349 { 2, "end loop", ASN1_EOC, ASN1_END }, /* 11 */
350 { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 12 */
351 { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 13 */
352 { 0, "exit", ASN1_EOC, ASN1_EXIT }
353 };
354 #define PKCS10_CERT_REQUEST_INFO 1
355 #define PKCS10_VERSION 2
356 #define PKCS10_SUBJECT 3
357 #define PKCS10_SUBJECT_PUBLIC_KEY_INFO 4
358 #define PKCS10_ATTR_TYPE 7
359 #define PKCS10_ATTR_VALUE 9
360 #define PKCS10_ALGORITHM 12
361 #define PKCS10_SIGNATURE 13
362
363 /**
364 * Parses a PKCS#10 certificate request
365 */
366 static bool parse_certificate_request(private_x509_pkcs10_t *this)
367 {
368 asn1_parser_t *parser;
369 chunk_t object;
370 int objectID;
371 int attr_oid = OID_UNKNOWN;
372 bool success = FALSE;
373
374 parser = asn1_parser_create(certificationRequestObjects, this->encoding);
375
376 while (parser->iterate(parser, &objectID, &object))
377 {
378 u_int level = parser->get_level(parser)+1;
379
380 switch (objectID)
381 {
382 case PKCS10_CERT_REQUEST_INFO:
383 this->certificationRequestInfo = object;
384 break;
385 case PKCS10_VERSION:
386 if (object.len > 0 && *object.ptr != 0)
387 {
388 DBG1(DBG_LIB, "PKCS#10 certificate request format is "
389 "not version 1");
390 goto end;
391 }
392 break;
393 case PKCS10_SUBJECT:
394 this->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object);
395 DBG2(DBG_LIB, " '%Y'", this->subject);
396 break;
397 case PKCS10_SUBJECT_PUBLIC_KEY_INFO:
398 this->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY,
399 KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END);
400 if (this->public_key == NULL)
401 {
402 goto end;
403 }
404 break;
405 case PKCS10_ATTR_TYPE:
406 attr_oid = asn1_known_oid(object);
407 break;
408 case PKCS10_ATTR_VALUE:
409 switch (attr_oid)
410 {
411 case OID_EXTENSION_REQUEST:
412 if (!parse_extension_request(this, object, level))
413 {
414 goto end;
415 }
416 break;
417 case OID_CHALLENGE_PASSWORD:
418 if (!parse_challengePassword(this, object, level))
419 {
420 goto end;
421 }
422 break;
423 default:
424 break;
425 }
426 break;
427 case PKCS10_ALGORITHM:
428 this->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL);
429 break;
430 case PKCS10_SIGNATURE:
431 this->signature = object;
432 break;
433 default:
434 break;
435 }
436 }
437 success = parser->success(parser);
438
439 end:
440 parser->destroy(parser);
441 if (success)
442 {
443 /* check if the certificate request is self-signed */
444 if (issued_by(this, &this->public.interface.interface))
445 {
446 this->self_signed = TRUE;
447 }
448 else
449 {
450 DBG1(DBG_LIB, "certificate request is not self-signed");
451 success = FALSE;
452 }
453 }
454 return success;
455 }
456
457 METHOD(certificate_t, destroy, void,
458 private_x509_pkcs10_t *this)
459 {
460 if (ref_put(&this->ref))
461 {
462 this->subjectAltNames->destroy_offset(this->subjectAltNames,
463 offsetof(identification_t, destroy));
464 DESTROY_IF(this->subject);
465 DESTROY_IF(this->public_key);
466 chunk_free(&this->encoding);
467 if (!this->parsed)
468 { /* only parsed certificate requests point these fields to "encoded" */
469 chunk_free(&this->certificationRequestInfo);
470 chunk_free(&this->challengePassword);
471 chunk_free(&this->signature);
472 }
473 free(this);
474 }
475 }
476
477 /**
478 * create an empty but initialized PKCS#10 certificate request
479 */
480 static private_x509_pkcs10_t* create_empty(void)
481 {
482 private_x509_pkcs10_t *this;
483
484 INIT(this,
485 .public = {
486 .interface = {
487 .interface = {
488 .get_type = _get_type,
489 .get_subject = _get_subject,
490 .get_issuer = _get_subject,
491 .has_subject = _has_subject,
492 .has_issuer = _has_subject,
493 .issued_by = _issued_by,
494 .get_public_key = _get_public_key,
495 .get_validity = _get_validity,
496 .get_encoding = _get_encoding,
497 .equals = _equals,
498 .get_ref = _get_ref,
499 .destroy = _destroy,
500 },
501 .get_challengePassword = _get_challengePassword,
502 .create_subjectAltName_enumerator = _create_subjectAltName_enumerator,
503 },
504 },
505 .subjectAltNames = linked_list_create(),
506 .ref = 1,
507 );
508
509 return this;
510 }
511
512 /**
513 * Generate and sign a new certificate request
514 */
515 static bool generate(private_x509_pkcs10_t *cert, private_key_t *sign_key,
516 int digest_alg)
517 {
518 chunk_t key_info, subjectAltNames, attributes;
519 chunk_t extensionRequest = chunk_empty;
520 chunk_t challengePassword = chunk_empty;
521 signature_scheme_t scheme;
522 identification_t *subject;
523
524 subject = cert->subject;
525 cert->public_key = sign_key->get_public_key(sign_key);
526
527 /* select signature scheme */
528 cert->algorithm = hasher_signature_algorithm_to_oid(digest_alg,
529 sign_key->get_type(sign_key));
530 if (cert->algorithm == OID_UNKNOWN)
531 {
532 return FALSE;
533 }
534 scheme = signature_scheme_from_oid(cert->algorithm);
535
536 if (!cert->public_key->get_encoding(cert->public_key,
537 PUBKEY_SPKI_ASN1_DER, &key_info))
538 {
539 return FALSE;
540 }
541
542 /* encode subjectAltNames */
543 subjectAltNames = x509_build_subjectAltNames(cert->subjectAltNames);
544
545 if (subjectAltNames.ptr)
546 {
547 extensionRequest = asn1_wrap(ASN1_SEQUENCE, "mm",
548 asn1_build_known_oid(OID_EXTENSION_REQUEST),
549 asn1_wrap(ASN1_SET, "m",
550 asn1_wrap(ASN1_SEQUENCE, "m", subjectAltNames)
551 ));
552 }
553 if (cert->challengePassword.len > 0)
554 {
555 asn1_t type = asn1_is_printablestring(cert->challengePassword) ?
556 ASN1_PRINTABLESTRING : ASN1_T61STRING;
557
558 challengePassword = asn1_wrap(ASN1_SEQUENCE, "mm",
559 asn1_build_known_oid(OID_CHALLENGE_PASSWORD),
560 asn1_wrap(ASN1_SET, "m",
561 asn1_simple_object(type, cert->challengePassword)
562 )
563 );
564 }
565 attributes = asn1_wrap(ASN1_CONTEXT_C_0, "mm", extensionRequest,
566 challengePassword);
567
568 cert->certificationRequestInfo = asn1_wrap(ASN1_SEQUENCE, "ccmm",
569 ASN1_INTEGER_0,
570 subject->get_encoding(subject),
571 key_info,
572 attributes);
573
574 if (!sign_key->sign(sign_key, scheme, cert->certificationRequestInfo,
575 &cert->signature))
576 {
577 return FALSE;
578 }
579
580 cert->encoding = asn1_wrap(ASN1_SEQUENCE, "cmm",
581 cert->certificationRequestInfo,
582 asn1_algorithmIdentifier(cert->algorithm),
583 asn1_bitstring("c", cert->signature));
584 return TRUE;
585 }
586
587 /**
588 * See header.
589 */
590 x509_pkcs10_t *x509_pkcs10_load(certificate_type_t type, va_list args)
591 {
592 chunk_t blob = chunk_empty;
593
594 while (TRUE)
595 {
596 switch (va_arg(args, builder_part_t))
597 {
598 case BUILD_BLOB_ASN1_DER:
599 blob = va_arg(args, chunk_t);
600 continue;
601 case BUILD_END:
602 break;
603 default:
604 return NULL;
605 }
606 break;
607 }
608
609 if (blob.ptr)
610 {
611 private_x509_pkcs10_t *cert = create_empty();
612
613 cert->encoding = chunk_clone(blob);
614 cert->parsed = TRUE;
615 if (parse_certificate_request(cert))
616 {
617 return &cert->public;
618 }
619 destroy(cert);
620 }
621 return NULL;
622 }
623
624 /**
625 * See header.
626 */
627 x509_pkcs10_t *x509_pkcs10_gen(certificate_type_t type, va_list args)
628 {
629 private_x509_pkcs10_t *cert;
630 private_key_t *sign_key = NULL;
631 hash_algorithm_t digest_alg = HASH_SHA1;
632
633 cert = create_empty();
634 while (TRUE)
635 {
636 switch (va_arg(args, builder_part_t))
637 {
638 case BUILD_SIGNING_KEY:
639 sign_key = va_arg(args, private_key_t*);
640 continue;
641 case BUILD_SUBJECT:
642 cert->subject = va_arg(args, identification_t*);
643 cert->subject = cert->subject->clone(cert->subject);
644 continue;
645 case BUILD_SUBJECT_ALTNAMES:
646 {
647 enumerator_t *enumerator;
648 identification_t *id;
649 linked_list_t *list;
650
651 list = va_arg(args, linked_list_t*);
652 enumerator = list->create_enumerator(list);
653 while (enumerator->enumerate(enumerator, &id))
654 {
655 cert->subjectAltNames->insert_last(cert->subjectAltNames,
656 id->clone(id));
657 }
658 enumerator->destroy(enumerator);
659 continue;
660 }
661 case BUILD_CHALLENGE_PWD:
662 cert->challengePassword = chunk_clone(va_arg(args, chunk_t));
663 continue;
664 case BUILD_DIGEST_ALG:
665 digest_alg = va_arg(args, int);
666 continue;
667 case BUILD_END:
668 break;
669 default:
670 destroy(cert);
671 return NULL;
672 }
673 break;
674 }
675
676 if (sign_key && generate(cert, sign_key, digest_alg))
677 {
678 return &cert->public;
679 }
680 destroy(cert);
681 return NULL;
682 }
683