2 * Copyright (C) 2005 Jan Hutter, Martin Willi
3 * Copyright (C) 2009 Andreas Steffen
5 * HSR Hochschule fuer Technik Rapperswil
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>.
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
18 #include "x509_pkcs10.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>
29 typedef struct private_x509_pkcs10_t private_x509_pkcs10_t
;
32 * Private data of a x509_pkcs10_t object.
34 struct private_x509_pkcs10_t
{
36 * Public interface for this certificate.
41 * PKCS#10 certificate request encoding in ASN.1 DER format
46 * PKCS#10 request body over which signature is computed
48 chunk_t certificationRequestInfo
;
51 * Version of the PKCS#10 certificate request
56 * ID representing the certificate subject
58 identification_t
*subject
;
61 * List of subjectAltNames as identification_t
63 linked_list_t
*subjectAltNames
;
66 * certificate's embedded public key
68 public_key_t
*public_key
;
73 chunk_t challengePassword
;
86 * Is the certificate request self-signed?
91 * Certificate request parsed from blob/file?
102 * Implementation of certificate_t.get_type.
104 static certificate_type_t
get_type(private_x509_pkcs10_t
*this)
106 return CERT_PKCS10_REQUEST
;
110 * Implementation of certificate_t.get_subject and get_issuer.
112 static identification_t
* get_subject(private_x509_pkcs10_t
*this)
114 return this->subject
;
118 * Implementation of certificate_t.has_subject and has_issuer.
120 static id_match_t
has_subject(private_x509_pkcs10_t
*this, identification_t
*subject
)
122 return this->subject
->matches(this->subject
, subject
);
126 * Implementation of certificate_t.issued_by.
128 static bool issued_by(private_x509_pkcs10_t
*this, certificate_t
*issuer
)
131 signature_scheme_t scheme
;
133 if (&this->public.interface
.interface
!= issuer
)
137 if (this->self_signed
)
142 /* determine signature scheme */
143 scheme
= signature_scheme_from_oid(this->algorithm
);
144 if (scheme
== SIGN_UNKNOWN
)
149 /* get the public key contained in the certificate request */
150 key
= this->public_key
;
155 return key
->verify(key
, scheme
, this->certificationRequestInfo
,
160 * Implementation of certificate_t.get_public_key.
162 static public_key_t
* get_public_key(private_x509_pkcs10_t
*this)
164 this->public_key
->get_ref(this->public_key
);
165 return this->public_key
;
169 * Implementation of certificate_t.get_validity.
171 static bool get_validity(private_x509_pkcs10_t
*this, time_t *when
,
172 time_t *not_before
, time_t *not_after
)
186 * Implementation of certificate_t.is_newer.
188 static bool is_newer(certificate_t
*this, certificate_t
*that
)
194 * Implementation of certificate_t.get_encoding.
196 static chunk_t
get_encoding(private_x509_pkcs10_t
*this)
198 return chunk_clone(this->encoding
);
202 * Implementation of certificate_t.equals.
204 static bool equals(private_x509_pkcs10_t
*this, certificate_t
*other
)
209 if (this == (private_x509_pkcs10_t
*)other
)
213 if (other
->get_type(other
) != CERT_PKCS10_REQUEST
)
217 if (other
->equals
== (void*)equals
)
218 { /* skip allocation if we have the same implementation */
219 return chunk_equals(this->encoding
, ((private_x509_pkcs10_t
*)other
)->encoding
);
221 encoding
= other
->get_encoding(other
);
222 equal
= chunk_equals(this->encoding
, encoding
);
228 * Implementation of certificate_t.get_ref
230 static private_x509_pkcs10_t
* get_ref(private_x509_pkcs10_t
*this)
237 * Implementation of certificate_t.get_challengePassword.
239 static chunk_t
get_challengePassword(private_x509_pkcs10_t
*this)
241 return this->challengePassword
;
245 * Implementation of pkcs10_t.create_subjectAltName_enumerator.
247 static enumerator_t
* create_subjectAltName_enumerator(private_x509_pkcs10_t
*this)
249 return this->subjectAltNames
->create_enumerator(this->subjectAltNames
);
253 * Imported from x509_cert.c
255 extern void x509_parse_generalNames(chunk_t blob
, int level0
, bool implicit
, linked_list_t
*list
);
258 * ASN.1 definition of a PKCS#10 extension request
260 static const asn1Object_t extensionRequestObjects
[] = {
261 { 0, "extensions", ASN1_SEQUENCE
, ASN1_LOOP
}, /* 0 */
262 { 1, "extension", ASN1_SEQUENCE
, ASN1_NONE
}, /* 1 */
263 { 2, "extnID", ASN1_OID
, ASN1_BODY
}, /* 2 */
264 { 2, "critical", ASN1_BOOLEAN
, ASN1_DEF
|ASN1_BODY
}, /* 3 */
265 { 2, "extnValue", ASN1_OCTET_STRING
, ASN1_BODY
}, /* 4 */
266 { 1, "end loop", ASN1_EOC
, ASN1_END
}, /* 5 */
267 { 0, "exit", ASN1_EOC
, ASN1_EXIT
}
269 #define PKCS10_EXTN_ID 2
270 #define PKCS10_EXTN_CRITICAL 3
271 #define PKCS10_EXTN_VALUE 4
274 * Parses a PKCS#10 extension request
276 static bool parse_extension_request(private_x509_pkcs10_t
*this, chunk_t blob
, int level0
)
278 asn1_parser_t
*parser
;
281 int extn_oid
= OID_UNKNOWN
;
282 bool success
= FALSE
;
285 parser
= asn1_parser_create(extensionRequestObjects
, blob
);
286 parser
->set_top_level(parser
, level0
);
288 while (parser
->iterate(parser
, &objectID
, &object
))
290 u_int level
= parser
->get_level(parser
)+1;
295 extn_oid
= asn1_known_oid(object
);
297 case PKCS10_EXTN_CRITICAL
:
298 critical
= object
.len
&& *object
.ptr
;
299 DBG2(" %s", critical ?
"TRUE" : "FALSE");
301 case PKCS10_EXTN_VALUE
:
305 case OID_SUBJECT_ALT_NAME
:
306 x509_parse_generalNames(object
, level
, FALSE
,
307 this->subjectAltNames
);
318 success
= parser
->success(parser
);
319 parser
->destroy(parser
);
324 * Parses a PKCS#10 challenge password
326 static bool parse_challengePassword(private_x509_pkcs10_t
*this, chunk_t blob
, int level
)
332 DBG1("L%d - challengePassword: ASN.1 object smaller than 2 octets",
337 if (tag
< ASN1_UTF8STRING
|| tag
> ASN1_IA5STRING
)
339 DBG1("L%d - challengePassword: ASN.1 object is not a character string",
343 if (asn1_length(&blob
) == ASN1_INVALID_LENGTH
)
345 DBG1("L%d - challengePassword: ASN.1 object has an invalid length",
349 DBG2("L%d - challengePassword:", level
);
350 DBG4(" '%.*s'", blob
.len
, blob
.ptr
);
355 * ASN.1 definition of a PKCS#10 certificate request
357 static const asn1Object_t certificationRequestObjects
[] = {
358 { 0, "certificationRequest", ASN1_SEQUENCE
, ASN1_OBJ
}, /* 0 */
359 { 1, "certificationRequestInfo", ASN1_SEQUENCE
, ASN1_OBJ
}, /* 1 */
360 { 2, "version", ASN1_INTEGER
, ASN1_RAW
}, /* 2 */
361 { 2, "subject", ASN1_SEQUENCE
, ASN1_OBJ
}, /* 3 */
362 { 2, "subjectPublicKeyInfo", ASN1_SEQUENCE
, ASN1_RAW
}, /* 4 */
363 { 2, "attributes", ASN1_CONTEXT_C_0
, ASN1_LOOP
}, /* 5 */
364 { 3, "attribute", ASN1_SEQUENCE
, ASN1_NONE
}, /* 6 */
365 { 4, "type", ASN1_OID
, ASN1_BODY
}, /* 7 */
366 { 4, "values", ASN1_SET
, ASN1_LOOP
}, /* 8 */
367 { 5, "value", ASN1_EOC
, ASN1_RAW
}, /* 9 */
368 { 4, "end loop", ASN1_EOC
, ASN1_END
}, /* 10 */
369 { 2, "end loop", ASN1_EOC
, ASN1_END
}, /* 11 */
370 { 1, "signatureAlgorithm", ASN1_EOC
, ASN1_RAW
}, /* 12 */
371 { 1, "signature", ASN1_BIT_STRING
, ASN1_BODY
}, /* 13 */
372 { 0, "exit", ASN1_EOC
, ASN1_EXIT
}
374 #define PKCS10_CERT_REQUEST_INFO 1
375 #define PKCS10_VERSION 2
376 #define PKCS10_SUBJECT 3
377 #define PKCS10_SUBJECT_PUBLIC_KEY_INFO 4
378 #define PKCS10_ATTR_TYPE 7
379 #define PKCS10_ATTR_VALUE 9
380 #define PKCS10_ALGORITHM 12
381 #define PKCS10_SIGNATURE 13
384 * Parses a PKCS#10 certificate request
386 static bool parse_certificate_request(private_x509_pkcs10_t
*this)
388 asn1_parser_t
*parser
;
391 int attr_oid
= OID_UNKNOWN
;
392 bool success
= FALSE
;
394 parser
= asn1_parser_create(certificationRequestObjects
, this->encoding
);
396 while (parser
->iterate(parser
, &objectID
, &object
))
398 u_int level
= parser
->get_level(parser
)+1;
402 case PKCS10_CERT_REQUEST_INFO
:
403 this->certificationRequestInfo
= object
;
406 this->version
= (object
.len
) ?
(1+(u_int
)*object
.ptr
) : 1;
407 DBG2(" v%d", this->version
);
411 this->subject
= identification_create_from_encoding(ID_DER_ASN1_DN
, object
);
412 DBG2(" '%Y'", this->subject
);
414 case PKCS10_SUBJECT_PUBLIC_KEY_INFO
:
415 this->public_key
= lib
->creds
->create(lib
->creds
, CRED_PUBLIC_KEY
,
416 KEY_ANY
, BUILD_BLOB_ASN1_DER
, object
, BUILD_END
);
417 if (this->public_key
== NULL
)
422 case PKCS10_ATTR_TYPE
:
423 attr_oid
= asn1_known_oid(object
);
425 case PKCS10_ATTR_VALUE
:
428 case OID_EXTENSION_REQUEST
:
429 if (!parse_extension_request(this, object
, level
))
434 case OID_CHALLENGE_PASSWORD
:
435 if (!parse_challengePassword(this, object
, level
))
444 case PKCS10_ALGORITHM
:
445 this->algorithm
= asn1_parse_algorithmIdentifier(object
, level
, NULL
);
447 case PKCS10_SIGNATURE
:
448 this->signature
= object
;
454 success
= parser
->success(parser
);
457 parser
->destroy(parser
);
460 /* check if the certificate request is self-signed */
461 if (issued_by(this, &this->public.interface
.interface
))
463 this->self_signed
= TRUE
;
467 DBG1("certificate request is not self-signed");
475 * Implementation of certificate_t.destroy
477 static void destroy(private_x509_pkcs10_t
*this)
479 if (ref_put(&this->ref
))
481 this->subjectAltNames
->destroy_offset(this->subjectAltNames
,
482 offsetof(identification_t
, destroy
));
483 DESTROY_IF(this->subject
);
484 DESTROY_IF(this->public_key
);
485 chunk_free(&this->encoding
);
487 { /* only parsed certificate requests point these fields to "encoded" */
488 chunk_free(&this->certificationRequestInfo
);
489 chunk_free(&this->challengePassword
);
490 chunk_free(&this->signature
);
497 * create an empty but initialized PKCS#10 certificate request
499 static private_x509_pkcs10_t
* create_empty(void)
501 private_x509_pkcs10_t
*this = malloc_thing(private_x509_pkcs10_t
);
503 this->public.interface
.interface
.get_type
= (certificate_type_t (*) (certificate_t
*))get_type
;
504 this->public.interface
.interface
.get_subject
= (identification_t
* (*) (certificate_t
*))get_subject
;
505 this->public.interface
.interface
.get_issuer
= (identification_t
* (*) (certificate_t
*))get_subject
;
506 this->public.interface
.interface
.has_subject
= (id_match_t (*) (certificate_t
*, identification_t
*))has_subject
;
507 this->public.interface
.interface
.has_issuer
= (id_match_t (*) (certificate_t
*, identification_t
*))has_subject
;
508 this->public.interface
.interface
.issued_by
= (bool (*) (certificate_t
*, certificate_t
*))issued_by
;
509 this->public.interface
.interface
.get_public_key
= (public_key_t
* (*) (certificate_t
*))get_public_key
;
510 this->public.interface
.interface
.get_validity
= (bool (*) (certificate_t
*, time_t*, time_t*, time_t*))get_validity
;
511 this->public.interface
.interface
.is_newer
= (bool (*) (certificate_t
*,certificate_t
*))is_newer
;
512 this->public.interface
.interface
.get_encoding
= (chunk_t (*) (certificate_t
*))get_encoding
;
513 this->public.interface
.interface
.equals
= (bool (*)(certificate_t
*, certificate_t
*))equals
;
514 this->public.interface
.interface
.get_ref
= (certificate_t
* (*)(certificate_t
*))get_ref
;
515 this->public.interface
.interface
.destroy
= (void (*)(certificate_t
*))destroy
;
516 this->public.interface
.get_challengePassword
= (chunk_t (*)(pkcs10_t
*))get_challengePassword
;
517 this->public.interface
.create_subjectAltName_enumerator
= (enumerator_t
* (*)(pkcs10_t
*))create_subjectAltName_enumerator
;
519 this->encoding
= chunk_empty
;
520 this->certificationRequestInfo
= chunk_empty
;
521 this->subject
= NULL
;
522 this->public_key
= NULL
;
523 this->subjectAltNames
= linked_list_create();
524 this->challengePassword
= chunk_empty
;
525 this->signature
= chunk_empty
;
527 this->self_signed
= FALSE
;
528 this->parsed
= FALSE
;
534 * Generate and sign a new certificate
536 static bool generate(private_x509_pkcs10_t
*cert
, private_key_t
*sign_key
,
546 x509_pkcs10_t
*x509_pkcs10_load(certificate_type_t type
, va_list args
)
548 chunk_t blob
= chunk_empty
;
552 switch (va_arg(args
, builder_part_t
))
554 case BUILD_BLOB_ASN1_DER
:
555 blob
= va_arg(args
, chunk_t
);
567 private_x509_pkcs10_t
*cert
= create_empty();
569 cert
->encoding
= chunk_clone(blob
);
571 if (parse_certificate_request(cert
))
573 return &cert
->public;
583 x509_pkcs10_t
*x509_pkcs10_gen(certificate_type_t type
, va_list args
)
585 private_x509_pkcs10_t
*cert
;
586 private_key_t
*sign_key
= NULL
;
587 hash_algorithm_t digest_alg
= HASH_SHA1
;
589 cert
= create_empty();
592 switch (va_arg(args
, builder_part_t
))
594 case BUILD_SIGNING_KEY
:
595 sign_key
= va_arg(args
, private_key_t
*);
597 case BUILD_PUBLIC_KEY
:
598 cert
->public_key
= va_arg(args
, public_key_t
*);
599 cert
->public_key
->get_ref(cert
->public_key
);
602 cert
->subject
= va_arg(args
, identification_t
*);
603 cert
->subject
= cert
->subject
->clone(cert
->subject
);
605 case BUILD_SUBJECT_ALTNAMES
:
607 enumerator_t
*enumerator
;
608 identification_t
*id
;
611 list
= va_arg(args
, linked_list_t
*);
612 enumerator
= list
->create_enumerator(list
);
613 while (enumerator
->enumerate(enumerator
, &id
))
615 cert
->subjectAltNames
->insert_last(
616 cert
->subjectAltNames
, id
->clone(id
));
618 enumerator
->destroy(enumerator
);
621 case BUILD_DIGEST_ALG
:
622 digest_alg
= va_arg(args
, int);
633 if (sign_key
&& generate(cert
, sign_key
, digest_alg
))
635 return &cert
->public;