diff options
Diffstat (limited to 'src/libstrongswan/crypto/x509.c')
-rwxr-xr-x | src/libstrongswan/crypto/x509.c | 284 |
1 files changed, 145 insertions, 139 deletions
diff --git a/src/libstrongswan/crypto/x509.c b/src/libstrongswan/crypto/x509.c index dd82a493c..4c5e014c8 100755 --- a/src/libstrongswan/crypto/x509.c +++ b/src/libstrongswan/crypto/x509.c @@ -24,22 +24,21 @@ #include <sys/stat.h> #include <unistd.h> #include <string.h> +#include <printf.h> #include "x509.h" #include <types.h> +#include <library.h> #include <definitions.h> #include <asn1/oid.h> #include <asn1/asn1.h> #include <asn1/pem.h> -#include <utils/logger_manager.h> #include <utils/linked_list.h> #include <utils/identification.h> #define CERT_WARNING_INTERVAL 30 /* days */ -static logger_t *logger; - /** * Different kinds of generalNames */ @@ -422,7 +421,7 @@ static bool parse_basicConstraints(chunk_t blob, int level0) if (objectID == BASIC_CONSTRAINTS_CA) { isCA = object.len && *object.ptr; - logger->log(logger, CONTROL|LEVEL2, " %s", isCA ? "TRUE" : "FALSE"); + DBG2(" %s", isCA ? "TRUE" : "FALSE"); } objectID++; } @@ -519,7 +518,7 @@ static identification_t *parse_generalName(chunk_t blob, int level0) if (id_type != ID_ANY) { identification_t *gn = identification_create_from_encoding(id_type, object); - logger->log(logger, CONTROL|LEVEL2, " '%D'", gn); + DBG2(" '%D'", gn); return gn; } objectID++; @@ -670,7 +669,7 @@ static void parse_authorityInfoAccess(chunk_t blob, int level0, chunk_t *accessL { if (asn1_length(&object) == ASN1_INVALID_LENGTH) return; - logger->log(logger, CONTROL|LEVEL2, " '%.*s'",(int)object.len, object.ptr); + DBG2(" '%.*s'",(int)object.len, object.ptr); /* only HTTP(S) URIs accepted */ if (strncasecmp(object.ptr, "http", 4) == 0) { @@ -678,7 +677,7 @@ static void parse_authorityInfoAccess(chunk_t blob, int level0, chunk_t *accessL return; } } - logger->log(logger, ERROR|LEVEL2, "ignoring OCSP InfoAccessLocation with unkown protocol"); + DBG2("ignoring OCSP InfoAccessLocation with unkown protocol"); break; default: /* unkown accessMethod, ignoring */ @@ -779,7 +778,7 @@ bool parse_x509cert(chunk_t blob, u_int level0, private_x509_t *cert) break; case X509_OBJ_VERSION: cert->version = (object.len) ? (1+(u_int)*object.ptr) : 1; - logger->log(logger, CONTROL|LEVEL2, " v%d", cert->version); + DBG2(" v%d", cert->version); break; case X509_OBJ_SERIAL_NUMBER: cert->serialNumber = object; @@ -789,7 +788,7 @@ bool parse_x509cert(chunk_t blob, u_int level0, private_x509_t *cert) break; case X509_OBJ_ISSUER: cert->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object); - logger->log(logger, CONTROL|LEVEL1, " '%D'", cert->issuer); + DBG2(" '%D'", cert->issuer); break; case X509_OBJ_NOT_BEFORE: cert->notBefore = parse_time(object, level); @@ -799,12 +798,12 @@ bool parse_x509cert(chunk_t blob, u_int level0, private_x509_t *cert) break; case X509_OBJ_SUBJECT: cert->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object); - logger->log(logger, CONTROL|LEVEL1, " '%D'", cert->subject); + DBG2(" '%D'", cert->subject); break; case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM: if (parse_algorithmIdentifier(object, level, NULL) != OID_RSA_ENCRYPTION) { - logger->log(logger, ERROR|LEVEL1, " unsupported public key algorithm"); + DBG2(" unsupported public key algorithm"); return FALSE; } break; @@ -816,7 +815,7 @@ bool parse_x509cert(chunk_t blob, u_int level0, private_x509_t *cert) } else { - logger->log(logger, ERROR|LEVEL1, " invalid RSA public key format"); + DBG2(" invalid RSA public key format"); return FALSE; } break; @@ -828,7 +827,7 @@ bool parse_x509cert(chunk_t blob, u_int level0, private_x509_t *cert) break; case X509_OBJ_CRITICAL: critical = object.len && *object.ptr; - logger->log(logger, ERROR|LEVEL2, " %s", critical ? "TRUE" : "FALSE"); + DBG2(" %s", critical ? "TRUE" : "FALSE"); break; case X509_OBJ_EXTN_VALUE: { @@ -886,27 +885,26 @@ bool parse_x509cert(chunk_t blob, u_int level0, private_x509_t *cert) */ static err_t is_valid(const private_x509_t *this, time_t *until) { - char buf[TIMETOA_BUF]; - time_t current_time = time(NULL); - timetoa(buf, BUF_LEN, &this->notBefore, TRUE); - logger->log(logger, CONTROL|LEVEL1, " not before : %s", buf); - timetoa(buf, BUF_LEN, ¤t_time, TRUE); - logger->log(logger, CONTROL|LEVEL1, " current time: %s", buf); - timetoa(buf, BUF_LEN, &this->notAfter, TRUE); - logger->log(logger, CONTROL|LEVEL1, " not after : %s", buf); - - if (until != NULL - && (*until == UNDEFINED_TIME || this->notAfter < *until)) + DBG2(" not before : %T", this->notBefore); + DBG2(" current time: %T", current_time); + DBG2(" not after : %T", this->notAfter); + + if (until != NULL && + (*until == UNDEFINED_TIME || this->notAfter < *until)) { *until = this->notAfter; } if (current_time < this->notBefore) + { return "is not valid yet"; + } if (current_time > this->notAfter) + { return "has expired"; - logger->log(logger, CONTROL|LEVEL1, " certificate is valid", buf); + } + DBG2(" certificate is valid"); return NULL; } @@ -1049,153 +1047,165 @@ static bool verify(const private_x509_t *this, const rsa_public_key_t *signer) } /** - * destroy + * output handler in printf() */ -static void destroy(private_x509_t *this) +static int print(FILE *stream, const struct printf_info *info, + const void *const *args) { - identification_t *id; - while (this->subjectAltNames->remove_last(this->subjectAltNames, (void**)&id) == SUCCESS) + private_x509_t *this = *((private_x509_t**)(args[0])); + iterator_t *iterator; + identification_t *san; + chunk_t chunk; + bool utc = TRUE; + int written = 0; + + if (info->alt) { - id->destroy(id); + utc = *((bool*)(args[1])); } - this->subjectAltNames->destroy(this->subjectAltNames); - - while (this->crlDistributionPoints->remove_last(this->crlDistributionPoints, (void**)&id) == SUCCESS) + + if (this == NULL) { - id->destroy(id); + return fprintf(stream, "(null)"); } - this->crlDistributionPoints->destroy(this->crlDistributionPoints); - - if (this->issuer) - this->issuer->destroy(this->issuer); - - if (this->subject) - this->subject->destroy(this->subject); - - if (this->public_key) - this->public_key->destroy(this->public_key); - - free(this->certificate.ptr); - free(this); -} - -/** - * checks if the expiration date has been reached and warns during the - * warning_interval of the imminent expiration. - * strict=TRUE declares a fatal error, strict=FALSE issues a warning upon expiry. - */ -char* check_expiry(time_t expiration_date, int warning_interval, bool strict) -{ - int time_left; + + /* determine the current time */ + time_t now = time(NULL); - if (expiration_date == UNDEFINED_TIME) + written += fprintf(stream, " subject: %D\n", this->subject); + if (this->subjectAltNames->get_count(this->subjectAltNames) > 0) { - return "ok (expires never)"; + written += fprintf(stream, " altNames: "); + iterator = this->subjectAltNames->create_iterator(this->subjectAltNames, TRUE); + while (iterator->iterate(iterator, (void**)&san)) + { + written += fprintf(stream, "%D, ", san); + } + iterator->destroy(iterator); + written += fprintf(stream, "\n"); + } + written += fprintf(stream, " issuer: '%D'\n", this->issuer); + written += fprintf(stream, " serial: '%#B'\n", &this->serialNumber); + written += fprintf(stream, " installed: %#T\n", this->installed, utc); + + written += fprintf(stream, " validity: not before %#T, ", + this->notBefore, utc); + if (now < this->notBefore) + { + written += fprintf(stream, "not valid yet (valid in %V)\n", + now, this->notBefore); } - time_left = (expiration_date - time(NULL)); - if (time_left < 0) + else { - return strict? "fatal (expired)" : "warning (expired)"; + written += fprintf(stream, "ok\n"); } + written += fprintf(stream, " not after %#T, ", + this->notAfter, utc); + if (now > this->notAfter) { - static char buf[35]; - const char* unit = "second"; - - if (time_left > 86400*warning_interval) - return "ok"; - - if (time_left > 172800) - { - time_left /= 86400; - unit = "day"; - } - else if (time_left > 7200) - { - time_left /= 3600; - unit = "hour"; - } - else if (time_left > 120) + written += fprintf(stream, "expired (since %V)\n", now, this->notAfter); + } + else + { + written += fprintf(stream, "ok"); + if (now > this->notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24) { - time_left /= 60; - unit = "minute"; + written += fprintf(stream, " (expires in %V)", now, this->notAfter); } - snprintf(buf, sizeof(buf), "warning (expires in %d %s%s)", time_left, unit, (time_left == 1)?"":"s"); - - /* TODO: This is not thread save and may result in corrupted strings. Rewrite this! */ - return buf; + written += fprintf(stream, " \n"); } -} - -/** - * log certificate - */ -static void log_certificate(const private_x509_t *this, logger_t *logger, bool utc, bool has_key) -{ - identification_t *subject = this->subject; - identification_t *issuer = this->issuer; - rsa_public_key_t *pubkey = this->public_key; - - char buf[BUF_LEN]; - char time_buf[TIMETOA_BUF]; - - /* determine the current time */ - time_t now = time(NULL); - - timetoa(time_buf, TIMETOA_BUF, &this->installed, utc); - logger->log(logger, CONTROL, "%s", time_buf); - logger->log(logger, CONTROL, " subject: '%D'", subject); - logger->log(logger, CONTROL, " issuer: '%D'", issuer); - chunk_to_hex(buf, BUF_LEN, this->serialNumber); - logger->log(logger, CONTROL, " serial: %s", buf); + chunk = this->public_key->get_keyid(this->public_key); + written += fprintf(stream, " keyid: %#B\n", &chunk); + if (this->subjectKeyID.ptr) + { + written += fprintf(stream, " subjkey: %#B\n", &this->subjectKeyID); + } + if (this->authKeyID.ptr) + { + written += fprintf(stream, " authkey: %#B\n", &this->authKeyID); + } + if (this->authKeySerialNumber.ptr) + { + written += fprintf(stream, " aserial: %#B\n", &this->authKeySerialNumber); + } - timetoa(time_buf, TIMETOA_BUF, &this->notBefore, utc); - logger->log(logger, CONTROL, " validity: not before %s %s", time_buf, - (this->notBefore < now)? "ok":"fatal (not valid yet)"); + written += fprintf(stream, " pubkey: RSA %d bits", BITS_PER_BYTE * + this->public_key->get_keysize(this->public_key)); + written += fprintf(stream, ", status %N", + cert_status_names, this->status); - timetoa(time_buf, TIMETOA_BUF, &this->notAfter, utc); - logger->log(logger, CONTROL, " not after %s %s", time_buf, - check_expiry(this->notAfter, CERT_WARNING_INTERVAL, TRUE)); - - timetoa(time_buf, TIMETOA_BUF, &this->until, utc); switch (this->status) { case CERT_GOOD: - snprintf(buf, BUF_LEN, " until %s", time_buf); + written += fprintf(stream, " until %#T", this->until, utc); break; case CERT_REVOKED: - snprintf(buf, BUF_LEN, " on %s", time_buf); + written += fprintf(stream, " on %#T", this->until, utc); break; case CERT_UNKNOWN: case CERT_UNDEFINED: case CERT_UNTRUSTED: default: - *buf = '\0'; + break; } - logger->log(logger, CONTROL, " pubkey: RSA %d bits%s, status %s%s", - BITS_PER_BYTE * pubkey->get_keysize(pubkey), - has_key? ", has private key":"", - enum_name(&cert_status_names, this->status), buf); - - chunk_to_hex(buf, BUF_LEN, pubkey->get_keyid(pubkey)); - logger->log(logger, CONTROL, " keyid: %s", buf); + return written; +} - if (this->subjectKeyID.ptr != NULL) +/** + * arginfo handler in printf() + */ +static int print_arginfo(const struct printf_info *info, size_t n, int *argtypes) +{ + if (info->alt) + { + if (n > 1) + { + argtypes[0] = PA_INT; + argtypes[1] = PA_INT; + } + return 2; + } + + if (n > 0) { - chunk_to_hex(buf, BUF_LEN, this->subjectKeyID); - logger->log(logger, CONTROL, " subjkey: %s", buf); + argtypes[0] = PA_INT; } - if (this->authKeyID.ptr != NULL) + return 1; +} + +/** + * register printf() handlers + */ +static void __attribute__ ((constructor))print_register() +{ + register_printf_function(X509_PRINTF_SPEC, print, print_arginfo); +} + +/** + * Implements x509_t.destroy + */ +static void destroy(private_x509_t *this) +{ + identification_t *id; + while (this->subjectAltNames->remove_last(this->subjectAltNames, (void**)&id) == SUCCESS) { - chunk_to_hex(buf, BUF_LEN, this->authKeyID); - logger->log(logger, CONTROL, " authkey: %s", buf); + id->destroy(id); } - if (this->authKeySerialNumber.ptr != NULL) + this->subjectAltNames->destroy(this->subjectAltNames); + + while (this->crlDistributionPoints->remove_last(this->crlDistributionPoints, (void**)&id) == SUCCESS) { - chunk_to_hex(buf, BUF_LEN, this->authKeySerialNumber); - logger->log(logger, CONTROL, " aserial: %s", buf); + id->destroy(id); } + this->crlDistributionPoints->destroy(this->crlDistributionPoints); + + DESTROY_IF(this->issuer); + DESTROY_IF(this->subject); + DESTROY_IF(this->public_key); + free(this->certificate.ptr); + free(this); } /* @@ -1235,10 +1245,6 @@ x509_t *x509_create_from_chunk(chunk_t chunk) this->public.get_status = (cert_status_t (*) (const x509_t*))get_status; this->public.verify = (bool (*) (const x509_t*,const rsa_public_key_t*))verify; this->public.destroy = (void (*) (x509_t*))destroy; - this->public.log_certificate = (void (*) (const x509_t*,logger_t*,bool,bool))log_certificate; - - /* we do not use a per-instance logger right now, since its not always accessible */ - logger = logger_manager->get_logger(logger_manager, ASN1); if (!parse_x509cert(chunk, 0, this)) { |