int GTHTTP_verifyTimestampHash(const GTTimestamp *ts, const GTDataHash *hash, const char *ext_url, GTTimestamp **ext_ts, const GTPublicationsFile *pub, const char *pub_url, int parse, GTVerificationInfo **ver) { int res = GT_UNKNOWN_ERROR; GTPublicationsFile *pub_tmp = NULL; GTPubFileVerificationInfo *pub_ver = NULL; GTVerificationInfo *ver_tmp = NULL; GTTimestamp *ext = NULL; int is_ext = 0, is_new = 0; if (ts == NULL || hash == NULL || ver == NULL) { res = GT_INVALID_ARGUMENT; goto cleanup; } if ((pub != NULL) + (pub_url != NULL) != 1) { res = GT_INVALID_ARGUMENT; goto cleanup; } /* Ensure we have a valid publications file. */ if (pub == NULL) { res = GTHTTP_getPublicationsFile(pub_url, &pub_tmp); if (res != GT_OK) { goto cleanup; } pub = pub_tmp; } res = GTPublicationsFile_verify(pub, &pub_ver); if (res != GT_OK) { goto cleanup; } /* Check internal consistency of the timestamp. */ res = GTTimestamp_verify(ts, parse, &ver_tmp); if (res != GT_OK) { goto cleanup; } if (ver_tmp == NULL || ver_tmp->implicit_data == NULL) { res = GT_UNKNOWN_ERROR; goto cleanup; } if (ver_tmp->verification_errors != GT_NO_FAILURES) { goto cleanup; } /* Check document hash. * GT_WRONG_DOCUMENT means the hash did not match. * Everything else is some sort of system error. */ res = GTTimestamp_checkDocumentHash(ts, hash); if (res == GT_OK) { ver_tmp->verification_status |= GT_DOCUMENT_HASH_CHECKED; } else if (res == GT_WRONG_DOCUMENT) { ver_tmp->verification_status |= GT_DOCUMENT_HASH_CHECKED; ver_tmp->verification_errors |= GT_WRONG_DOCUMENT_FAILURE; res = GT_OK; goto cleanup; } else { goto cleanup; } /* Whether the timestamp is extended. */ is_ext = ((ver_tmp->verification_status & GT_PUBLIC_KEY_SIGNATURE_PRESENT) == 0); /* Whether it is too new to be extended. */ is_new = (ver_tmp->implicit_data->registered_time > pub_ver->last_publication_time); /* If the timestamp is already extended, "promote" it. * If it is not extended, but is old enough, attempt to extend it. */ if (is_ext) { ext = (GTTimestamp *) ts; } else if (!is_new && ext_url != NULL) { res = GTHTTP_extendTimestamp(ts, ext_url, &ext); /* If extending fails because of infrastructure failure, fall * back to signing key check. Else report errors. */ if (res == GT_NONSTD_EXTEND_LATER || res == GT_NONSTD_EXTENSION_OVERDUE || (res >= GTHTTP_IMPL_BASE && res <= GTHTTP_HIGHEST)) { res = GT_OK; } if (res != GT_OK) { goto cleanup; } } /* If we now have a new timestamp, check internal consistency and document hash. */ if (ext != NULL && ext != ts) { /* Release the old verification info. */ GTVerificationInfo_free(ver_tmp); ver_tmp = NULL; /* Re-check consistency. */ res = GTTimestamp_verify(ext, parse, &ver_tmp); if (res != GT_OK) { goto cleanup; } if (ver_tmp == NULL || ver_tmp->implicit_data == NULL) { res = GT_UNKNOWN_ERROR; goto cleanup; } if (ver_tmp->verification_errors != GT_NO_FAILURES) { goto cleanup; } /* Re-check document hash. */ res = GTTimestamp_checkDocumentHash(ts, hash); if (res == GT_OK) { ver_tmp->verification_status |= GT_DOCUMENT_HASH_CHECKED; } else if (res == GT_WRONG_DOCUMENT) { ver_tmp->verification_status |= GT_DOCUMENT_HASH_CHECKED; ver_tmp->verification_errors |= GT_WRONG_DOCUMENT_FAILURE; res = GT_OK; goto cleanup; } else { goto cleanup; } } if (ext != NULL) { /* If we now have an extended timestamp, check publication. * GT_TRUST_POINT_NOT_FOUND and GT_INVALID_TRUST_POINT mean it did not match. * Everything else is some sort of system error. */ res = GTTimestamp_checkPublication(ext, pub); if (res == GT_OK) { ver_tmp->verification_status |= GT_PUBLICATION_CHECKED; } else if (res == GT_TRUST_POINT_NOT_FOUND || res == GT_INVALID_TRUST_POINT) { ver_tmp->verification_status |= GT_PUBLICATION_CHECKED; ver_tmp->verification_errors |= GT_NOT_VALID_PUBLICATION; res = GT_OK; } } else { /* Otherwise, check signing key. * GT_KEY_NOT_PUBLISHED and GT_CERT_TICKET_TOO_OLD mean key not valid. * Everything else is some sort of system error. */ res = GTTimestamp_checkPublicKey(ts, ver_tmp->implicit_data->registered_time, pub); if (res == GT_OK) { ver_tmp->verification_status |= GT_PUBLICATION_CHECKED; } else if (res == GT_KEY_NOT_PUBLISHED || res == GT_CERT_TICKET_TOO_OLD) { ver_tmp->verification_status |= GT_PUBLICATION_CHECKED; ver_tmp->verification_errors |= GT_NOT_VALID_PUBLIC_KEY_FAILURE; res = GT_OK; } } cleanup: if (res == GT_OK) { if (ext_ts != NULL && ext != NULL && ext != ts && ver_tmp->verification_errors == GT_NO_FAILURES) { *ext_ts = ext; ext = NULL; } *ver = ver_tmp; ver_tmp = NULL; } if (ext != ts) { GTTimestamp_free(ext); } GTVerificationInfo_free(ver_tmp); GTPubFileVerificationInfo_free(pub_ver); GTPublicationsFile_free(pub_tmp); return res; }
/* Helper function to create \p GTPubFileVerificationInfo. */ static int createPubFileVerificationInfo( const GTPublicationsFile *publications_file, GTPubFileVerificationInfo **verification_info) { int res = GT_UNKNOWN_ERROR; int tmp_res = GT_UNKNOWN_ERROR; GTPubFileVerificationInfo *tmp_info = NULL; const GTPublicationsFile_Cell *cell = NULL; GTPublicationsFile_Cell cell_buf; unsigned char *cert_der = NULL; size_t cert_der_len; char *tmp_cert = NULL; assert(publications_file != NULL); assert(verification_info != NULL); tmp_info = GT_malloc(sizeof(GTPubFileVerificationInfo)); if (tmp_info == NULL) { res = GT_OUT_OF_MEMORY; goto cleanup; } tmp_info->publications_count = publications_file->number_of_publications; tmp_info->key_hash_count = publications_file->number_of_key_hashes; tmp_info->certificate = NULL; if (tmp_info->publications_count < 1) { tmp_info->first_publication_time = -1; tmp_info->last_publication_time = -1; } else { tmp_res = getPublicationCell(publications_file, 0, &cell, &cell_buf); if (tmp_res != GT_OK) { res = tmp_res; goto cleanup; } tmp_info->first_publication_time = cell->publication_identifier; if (tmp_info->publications_count > 1) { tmp_res = getPublicationCell(publications_file, tmp_info->publications_count - 1, &cell, &cell_buf); if (tmp_res != GT_OK) { res = tmp_res; goto cleanup; } tmp_info->last_publication_time = cell->publication_identifier; } else { tmp_info->last_publication_time = tmp_info->first_publication_time; } } tmp_res = GTPublicationsFile_getSigningCert(publications_file, &cert_der, &cert_der_len); if (tmp_res != GT_OK) { res = tmp_res; goto cleanup; } tmp_cert = GT_base32Encode(cert_der, cert_der_len, 8); if (tmp_cert == NULL) { res = GT_OUT_OF_MEMORY; goto cleanup; } /* This string duplication is necessary because we dont want to return * OPENSSL_malloc()-ed data in public API. */ tmp_info->certificate = GT_malloc(strlen(tmp_cert) + 1); if (tmp_info->certificate == NULL) { res = GT_OUT_OF_MEMORY; goto cleanup; } strcpy(tmp_info->certificate, tmp_cert); *verification_info = tmp_info; tmp_info = NULL; res = GT_OK; cleanup: GTPubFileVerificationInfo_free(tmp_info); GT_free(cert_der); OPENSSL_free(tmp_cert); return res; }