diff options
Diffstat (limited to 'src/libstrongswan/plugins/x509/x509_cert.c')
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_cert.c | 400 |
1 files changed, 167 insertions, 233 deletions
diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c index ae2ba19f7..c68bd1d20 100644 --- a/src/libstrongswan/plugins/x509/x509_cert.c +++ b/src/libstrongswan/plugins/x509/x509_cert.c @@ -3,7 +3,7 @@ * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss * Copyright (C) 2002 Mario Strasser * Copyright (C) 2000-2006 Andreas Steffen - * Copyright (C) 2006-2008 Martin Willi + * Copyright (C) 2006-2009 Martin Willi * Copyright (C) 2008 Tobias Brunner * Hochschule fuer Technik Rapperswil * @@ -676,6 +676,11 @@ static const asn1Object_t certObjects[] = { #define X509_OBJ_SIGNATURE 25 /** + * forward declaration + */ +static bool issued_by(private_x509_cert_t *this, certificate_t *issuer); + +/** * Parses an X.509v3 certificate */ static bool parse_certificate(private_x509_cert_t *this) @@ -810,6 +815,25 @@ static bool parse_certificate(private_x509_cert_t *this) end: parser->destroy(parser); + if (success) + { + hasher_t *hasher; + + /* check if the certificate is self-signed */ + if (issued_by(this, &this->public.interface.interface)) + { + this->flags |= X509_SELF_SIGNED; + } + /* create certificate hash */ + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (hasher == NULL) + { + DBG1(" unable to create hash of certificate, SHA1 not supported"); + return NULL; + } + hasher->allocate_hash(hasher, this->encoding, &this->encoding_hash); + hasher->destroy(hasher); + } return success; } @@ -910,17 +934,18 @@ static bool issued_by(private_x509_cert_t *this, certificate_t *issuer) return FALSE; } - /* get the public key of the issuer */ - key = issuer->get_public_key(issuer); - /* determine signature scheme */ scheme = signature_scheme_from_oid(this->algorithm); - - if (scheme == SIGN_UNKNOWN || key == NULL) + if (scheme == SIGN_UNKNOWN) + { + return FALSE; + } + /* get the public key of the issuer */ + key = issuer->get_public_key(issuer); + if (!key) { return FALSE; } - /* TODO: add a lightweight check option (comparing auth/subject keyids only) */ valid = key->verify(key, scheme, this->tbsCertificate, this->signature); key->destroy(key); return valid; @@ -1150,63 +1175,10 @@ static private_x509_cert_t* create_empty(void) } /** - * create an X.509 certificate from a chunk - */ -static private_x509_cert_t *create_from_chunk(chunk_t chunk) -{ - hasher_t *hasher; - private_x509_cert_t *this = create_empty(); - - this->encoding = chunk; - this->parsed = TRUE; - if (!parse_certificate(this)) - { - destroy(this); - return NULL; - } - - /* check if the certificate is self-signed */ - if (issued_by(this, &this->public.interface.interface)) - { - this->flags |= X509_SELF_SIGNED; - } - - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (hasher == NULL) - { - DBG1(" unable to create hash of certificate, SHA1 not supported"); - destroy(this); - return NULL; - } - hasher->allocate_hash(hasher, this->encoding, &this->encoding_hash); - hasher->destroy(hasher); - - return this; -} - -typedef struct private_builder_t private_builder_t; -/** - * Builder implementation for certificate loading - */ -struct private_builder_t { - /** implements the builder interface */ - builder_t public; - /** loaded certificate */ - private_x509_cert_t *cert; - /** additional flags to enforce */ - x509_flag_t flags; - /** certificate to sign, if we generate a new cert */ - certificate_t *sign_cert; - /** private key to sign, if we generate a new cert */ - private_key_t *sign_key; - /** digest algorithm to be used for signature */ - hash_algorithm_t digest_alg; -}; - -/** * Generate and sign a new certificate */ -static bool generate(private_builder_t *this) +static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert, + private_key_t *sign_key, int digest_alg) { chunk_t extensions = chunk_empty; chunk_t basicConstraints = chunk_empty, subjectAltNames = chunk_empty; @@ -1218,11 +1190,11 @@ static bool generate(private_builder_t *this) enumerator_t *enumerator; identification_t *id; - subject = this->cert->subject; - if (this->sign_cert) + subject = cert->subject; + if (sign_cert) { - issuer = this->sign_cert->get_subject(this->sign_cert); - if (!this->cert->public_key) + issuer = sign_cert->get_subject(sign_cert); + if (!cert->public_key) { return FALSE; } @@ -1230,65 +1202,64 @@ static bool generate(private_builder_t *this) else { /* self signed */ issuer = subject; - if (!this->cert->public_key) + if (!cert->public_key) { - this->cert->public_key = this->sign_key->get_public_key(this->sign_key); + cert->public_key = sign_key->get_public_key(sign_key); } - this->flags |= X509_SELF_SIGNED; + cert->flags |= X509_SELF_SIGNED; } - this->cert->issuer = issuer->clone(issuer); - if (!this->cert->notBefore) + cert->issuer = issuer->clone(issuer); + if (!cert->notBefore) { - this->cert->notBefore = time(NULL); + cert->notBefore = time(NULL); } - if (!this->cert->notAfter) + if (!cert->notAfter) { /* defaults to 1 year from now */ - this->cert->notAfter = this->cert->notBefore + 60 * 60 * 24 * 365; + cert->notAfter = cert->notBefore + 60 * 60 * 24 * 365; } - this->cert->flags = this->flags; /* select signature scheme */ - switch (this->sign_key->get_type(this->sign_key)) + switch (sign_key->get_type(sign_key)) { case KEY_RSA: - switch (this->digest_alg) + switch (digest_alg) { case HASH_MD5: - this->cert->algorithm = OID_MD5_WITH_RSA; + cert->algorithm = OID_MD5_WITH_RSA; break; case HASH_SHA1: - this->cert->algorithm = OID_SHA1_WITH_RSA; + cert->algorithm = OID_SHA1_WITH_RSA; break; case HASH_SHA224: - this->cert->algorithm = OID_SHA224_WITH_RSA; + cert->algorithm = OID_SHA224_WITH_RSA; break; case HASH_SHA256: - this->cert->algorithm = OID_SHA256_WITH_RSA; + cert->algorithm = OID_SHA256_WITH_RSA; break; case HASH_SHA384: - this->cert->algorithm = OID_SHA384_WITH_RSA; + cert->algorithm = OID_SHA384_WITH_RSA; break; case HASH_SHA512: - this->cert->algorithm = OID_SHA512_WITH_RSA; + cert->algorithm = OID_SHA512_WITH_RSA; break; default: return FALSE; } break; case KEY_ECDSA: - switch (this->digest_alg) + switch (digest_alg) { case HASH_SHA1: - this->cert->algorithm = OID_ECDSA_WITH_SHA1; + cert->algorithm = OID_ECDSA_WITH_SHA1; break; case HASH_SHA256: - this->cert->algorithm = OID_ECDSA_WITH_SHA256; + cert->algorithm = OID_ECDSA_WITH_SHA256; break; case HASH_SHA384: - this->cert->algorithm = OID_ECDSA_WITH_SHA384; + cert->algorithm = OID_ECDSA_WITH_SHA384; break; case HASH_SHA512: - this->cert->algorithm = OID_ECDSA_WITH_SHA512; + cert->algorithm = OID_ECDSA_WITH_SHA512; break; default: return FALSE; @@ -1297,16 +1268,15 @@ static bool generate(private_builder_t *this) default: return FALSE; } - scheme = signature_scheme_from_oid(this->cert->algorithm); + scheme = signature_scheme_from_oid(cert->algorithm); - if (!this->cert->public_key->get_encoding(this->cert->public_key, - KEY_PUB_SPKI_ASN1_DER, &key_info)) + if (!cert->public_key->get_encoding(cert->public_key, + KEY_PUB_SPKI_ASN1_DER, &key_info)) { return FALSE; } - enumerator = this->cert->subjectAltNames->create_enumerator( - this->cert->subjectAltNames); + enumerator = cert->subjectAltNames->create_enumerator(cert->subjectAltNames); while (enumerator->enumerate(enumerator, &id)) { int context; @@ -1344,7 +1314,7 @@ static bool generate(private_builder_t *this) asn1_wrap(ASN1_SEQUENCE, "m", subjectAltNames))); } - if (this->flags & X509_CA) + if (cert->flags & X509_CA) { chunk_t yes, keyid; @@ -1357,8 +1327,8 @@ static bool generate(private_builder_t *this) asn1_wrap(ASN1_SEQUENCE, "m", asn1_wrap(ASN1_BOOLEAN, "c", yes)))); /* add subjectKeyIdentifier to CA certificates */ - if (this->cert->public_key->get_fingerprint(this->cert->public_key, - KEY_ID_PUBKEY_SHA1, &keyid)) + if (cert->public_key->get_fingerprint(cert->public_key, + KEY_ID_PUBKEY_SHA1, &keyid)) { subjectKeyIdentifier = asn1_wrap(ASN1_SEQUENCE, "mm", asn1_build_known_oid(OID_SUBJECT_KEY_ID), @@ -1366,12 +1336,11 @@ static bool generate(private_builder_t *this) asn1_wrap(ASN1_OCTET_STRING, "c", keyid))); } } - if (this->sign_key) + if (sign_key) { /* add the keyid authKeyIdentifier for non self-signed certificates */ chunk_t keyid; - if (this->sign_key->get_fingerprint(this->sign_key, - KEY_ID_PUBKEY_SHA1, &keyid)) + if (sign_key->get_fingerprint(sign_key, KEY_ID_PUBKEY_SHA1, &keyid)) { authKeyIdentifier = asn1_wrap(ASN1_SEQUENCE, "mm", asn1_build_known_oid(OID_AUTHORITY_KEY_ID), @@ -1388,181 +1357,146 @@ static bool generate(private_builder_t *this) authKeyIdentifier, subjectAltNames)); } - this->cert->tbsCertificate = asn1_wrap(ASN1_SEQUENCE, "mmmcmcmm", + cert->tbsCertificate = asn1_wrap(ASN1_SEQUENCE, "mmmcmcmm", asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2), - asn1_integer("c", this->cert->serialNumber), - asn1_algorithmIdentifier(this->cert->algorithm), + asn1_integer("c", cert->serialNumber), + asn1_algorithmIdentifier(cert->algorithm), issuer->get_encoding(issuer), asn1_wrap(ASN1_SEQUENCE, "mm", - asn1_from_time(&this->cert->notBefore, ASN1_UTCTIME), - asn1_from_time(&this->cert->notAfter, ASN1_UTCTIME)), + asn1_from_time(&cert->notBefore, ASN1_UTCTIME), + asn1_from_time(&cert->notAfter, ASN1_UTCTIME)), subject->get_encoding(subject), key_info, extensions); - if (!this->sign_key->sign(this->sign_key, scheme, - this->cert->tbsCertificate, &this->cert->signature)) + if (!sign_key->sign(sign_key, scheme, cert->tbsCertificate, &cert->signature)) { return FALSE; } - this->cert->encoding = asn1_wrap(ASN1_SEQUENCE, "cmm", - this->cert->tbsCertificate, - asn1_algorithmIdentifier(this->cert->algorithm), - asn1_bitstring("c", this->cert->signature)); + cert->encoding = asn1_wrap(ASN1_SEQUENCE, "cmm", cert->tbsCertificate, + asn1_algorithmIdentifier(cert->algorithm), + asn1_bitstring("c", cert->signature)); hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); if (!hasher) { return FALSE; } - hasher->allocate_hash(hasher, this->cert->encoding, - &this->cert->encoding_hash); + hasher->allocate_hash(hasher, cert->encoding, &cert->encoding_hash); hasher->destroy(hasher); return TRUE; } /** - * Implementation of builder_t.build + * See header. */ -static private_x509_cert_t *build(private_builder_t *this) +x509_cert_t *x509_cert_load(certificate_type_t type, va_list args) { - private_x509_cert_t *cert; + chunk_t blob = chunk_empty; - if (this->cert) + while (TRUE) { - this->cert->flags |= this->flags; - if (!this->cert->encoding.ptr) - { /* generate a new certificate */ - if (!this->sign_key || !generate(this)) - { - destroy(this->cert); - free(this); + switch (va_arg(args, builder_part_t)) + { + case BUILD_BLOB_ASN1_DER: + blob = va_arg(args, chunk_t); + continue; + case BUILD_END: + break; + default: return NULL; - } } + break; } - cert = this->cert; - free(this); - return cert; -} -/** - * Implementation of builder_t.add - */ -static void add(private_builder_t *this, builder_part_t part, ...) -{ - va_list args; - chunk_t chunk; - bool handled = TRUE; - - va_start(args, part); - switch (part) - { - case BUILD_BLOB_ASN1_DER: - chunk = va_arg(args, chunk_t); - this->cert = create_from_chunk(chunk_clone(chunk)); - break; - case BUILD_X509_FLAG: - this->flags = va_arg(args, x509_flag_t); - break; - case BUILD_SIGNING_KEY: - this->sign_key = va_arg(args, private_key_t*); - break; - case BUILD_SIGNING_CERT: - this->sign_cert = va_arg(args, certificate_t*); - break; - default: - /* all other parts need an empty cert */ - if (!this->cert) - { - this->cert = create_empty(); - } - handled = FALSE; - break; - } - if (handled) - { - va_end(args); - return; - } - - switch (part) + if (blob.ptr) { - case BUILD_PUBLIC_KEY: - { - public_key_t *key = va_arg(args, public_key_t*); - this->cert->public_key = key->get_ref(key); - break; - } - case BUILD_SUBJECT: - { - identification_t *id = va_arg(args, identification_t*); - this->cert->subject = id->clone(id); - break; - } - case BUILD_SUBJECT_ALTNAMES: - { - identification_t *id; - enumerator_t *enumerator; - linked_list_t *list = va_arg(args, linked_list_t*); + private_x509_cert_t *cert = create_empty(); - enumerator = list->create_enumerator(list); - while (enumerator->enumerate(enumerator, &id)) - { - this->cert->subjectAltNames->insert_last( - this->cert->subjectAltNames, id->clone(id)); - } - enumerator->destroy(enumerator); - break; - } - case BUILD_NOT_BEFORE_TIME: - this->cert->notBefore = va_arg(args, time_t); - break; - case BUILD_NOT_AFTER_TIME: - this->cert->notAfter = va_arg(args, time_t); - break; - case BUILD_SERIAL: + cert->encoding = chunk_clone(blob); + if (parse_certificate(cert)) { - chunk_t serial = va_arg(args, chunk_t); - this->cert->serialNumber = chunk_clone(serial); - break; + cert->parsed = TRUE; + return &cert->public; } - case BUILD_DIGEST_ALG: - this->digest_alg = va_arg(args, int); - break; - default: - /* abort if unsupported option */ - if (this->cert) - { - destroy(this->cert); - } - builder_cancel(&this->public); - break; + destroy(cert); } - va_end(args); + return NULL; } /** - * Builder construction function + * See header. */ -builder_t *x509_cert_builder(certificate_type_t type) +x509_cert_t *x509_cert_gen(certificate_type_t type, va_list args) { - private_builder_t *this; + private_x509_cert_t *cert; + certificate_t *sign_cert = NULL; + private_key_t *sign_key = NULL; + hash_algorithm_t digest_alg = HASH_SHA1; - if (type != CERT_X509) + cert = create_empty(); + while (TRUE) { - return NULL; - } - - this = malloc_thing(private_builder_t); + switch (va_arg(args, builder_part_t)) + { + case BUILD_X509_FLAG: + cert->flags |= va_arg(args, x509_flag_t); + continue; + case BUILD_SIGNING_KEY: + sign_key = va_arg(args, private_key_t*); + continue; + case BUILD_SIGNING_CERT: + sign_cert = va_arg(args, certificate_t*); + continue; + case BUILD_PUBLIC_KEY: + cert->public_key = va_arg(args, public_key_t*); + cert->public_key->get_ref(cert->public_key); + continue; + case BUILD_SUBJECT: + cert->subject = va_arg(args, identification_t*); + cert->subject = cert->subject->clone(cert->subject); + continue; + case BUILD_SUBJECT_ALTNAMES: + { + enumerator_t *enumerator; + identification_t *id; + linked_list_t *list; - this->cert = NULL; - this->flags = 0; - this->sign_cert = NULL; - this->sign_key = NULL; - this->digest_alg = HASH_SHA1; - this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; - this->public.build = (void*(*)(builder_t *this))build; + list = va_arg(args, linked_list_t*); + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &id)) + { + cert->subjectAltNames->insert_last( + cert->subjectAltNames, id->clone(id)); + } + enumerator->destroy(enumerator); + continue; + } + case BUILD_NOT_BEFORE_TIME: + cert->notBefore = va_arg(args, time_t); + continue; + case BUILD_NOT_AFTER_TIME: + cert->notAfter = va_arg(args, time_t); + continue; + case BUILD_SERIAL: + cert->serialNumber = chunk_clone(va_arg(args, chunk_t)); + continue; + case BUILD_DIGEST_ALG: + digest_alg = va_arg(args, int); + continue; + case BUILD_END: + break; + default: + destroy(cert); + return NULL; + } + break; + } - return &this->public; + if (sign_key && generate(cert, sign_cert, sign_key, digest_alg)) + { + return &cert->public; + } + destroy(cert); + return NULL; } |