static void on_feed_done_cb(void *data, struct sol_message_digest *md, struct sol_blob *input) { struct update_get_hash_handle *handle = data; char buf[CHUNK_SIZE], *blob_backend = NULL; struct sol_blob *blob = NULL; size_t size; bool last; int r; size = fread(buf, 1, sizeof(buf), handle->file); if (ferror(handle->file)) { SOL_WRN("Could not read file for feed hash algorithm"); goto err; } last = feof(handle->file); /* TODO Maybe this is a bug on sol_message_digest? Keeps calling on_feed_done * after send last chunk */ if (!size && last && input) { SOL_WRN("Nothing more to feed hash algorithm, ignoring on_feed_done request"); return; } blob_backend = malloc(size); SOL_NULL_CHECK_GOTO(blob_backend, err); blob = sol_blob_new(&SOL_BLOB_TYPE_DEFAULT, NULL, blob_backend, size); SOL_NULL_CHECK_GOTO(blob, err); memcpy(blob_backend, buf, size); r = sol_message_digest_feed(md, blob, last); SOL_INT_CHECK_GOTO(r, < 0, err); sol_blob_unref(blob); return; err: SOL_WRN("Could not feed data to check update file hash"); free(blob_backend); sol_blob_unref(blob); sol_message_digest_del(md); handle->cb((void *)handle->user_data, -EINVAL, NULL); delete_handle(handle); }
static void on_digest_ready_cb(void *data, struct sol_message_digest *md, struct sol_blob *output) { struct update_get_hash_handle *handle = data; struct sol_buffer buffer = SOL_BUFFER_INIT_EMPTY; struct sol_str_slice slice = sol_str_slice_from_blob(output); int r = 0; r = sol_buffer_append_as_base16(&buffer, slice, false); SOL_INT_CHECK_GOTO(r, < 0, end); end: handle->cb((void *)handle->user_data, r, (char *)buffer.data); sol_message_digest_del(md); sol_buffer_fini(&buffer); delete_handle(handle); }
static void on_digest_ready(void *data, struct sol_message_digest *handle, struct sol_blob *digest) { struct feed_ctx *ctx = data; struct sol_buffer buf; int r; sol_buffer_init(&buf); r = sol_buffer_append_as_base16(&buf, sol_str_slice_from_blob(digest), false); if (r == 0) { printf("%s\t%s\n", (char *)buf.data, ctx->file); } sol_buffer_fini(&buf); print_time(ctx, ctx->done, "final"); sol_message_digest_del(handle); free(ctx); pending--; if (pending == 0) sol_quit(); }
SOL_API struct sol_message_digest * sol_message_digest_new(const struct sol_message_digest_config *config) { int (*init_fn)(struct sol_message_digest *, const EVP_MD *, const struct sol_str_slice); struct sol_message_digest_common_new_params params; const EVP_MD *md; struct sol_message_digest *handle; int errno_bkp; errno = EINVAL; SOL_NULL_CHECK(config, NULL); SOL_NULL_CHECK(config->on_digest_ready, NULL); SOL_NULL_CHECK(config->algorithm, NULL); #ifndef SOL_NO_API_VERSION if (config->api_version != SOL_MESSAGE_DIGEST_CONFIG_API_VERSION) { SOL_WRN("sol_message_digest_config->api_version=%" PRIu16 ", " "expected version is %" PRIu16 ".", config->api_version, SOL_MESSAGE_DIGEST_CONFIG_API_VERSION); return NULL; } #endif if (!did_openssl_load_digests) { OpenSSL_add_all_digests(); did_openssl_load_digests = true; } params.config = config; params.ops = NULL; md = EVP_get_digestbyname(config->algorithm); if (md) { params.context_handle = EVP_MD_CTX_new(); params.context_free = (void (*)(void *))EVP_MD_CTX_free; init_fn = _sol_message_digest_evp_init; params.ops = &_sol_message_digest_evp_ops; SOL_DBG("using evp, md=%p, algorithm=\"%s\"", md, config->algorithm); } else if (streqn(config->algorithm, "hmac(", strlen("hmac("))) { const char *p = config->algorithm + strlen("hmac("); size_t len = strlen(p); params.context_handle = HMAC_CTX_new(); params.context_free = (void (*)(void *))HMAC_CTX_free; if (len > 1 && p[len - 1] == ')') { char *mdname = strndupa(p, len - 1); md = EVP_get_digestbyname(mdname); if (!md) { SOL_WRN("failed to get digest algorithm \"%s\" for \"%s\".", mdname, config->algorithm); return NULL; } init_fn = _sol_message_digest_hmac_init; params.ops = &_sol_message_digest_hmac_ops; SOL_DBG("using hmac, md=%p, algorithm=\"%s\"", md, mdname); } } if (!params.ops) { SOL_WRN("failed to get digest algorithm \"%s\".", config->algorithm); return NULL; } params.digest_size = EVP_MD_size(md); handle = sol_message_digest_common_new(params); SOL_NULL_CHECK(handle, NULL); errno = init_fn(handle, md, config->key); if (errno) goto error; return handle; error: errno_bkp = errno; sol_message_digest_del(handle); errno = errno_bkp; return NULL; }
static void startup(void) { const char *algorithm = "sha256"; const char *key = NULL; char **argv = sol_argv(); int i, argc = sol_argc(); size_t chunk_size = -1; if (argc < 2) { fprintf(stderr, "Usage:\n\t%s [-a <algorithm>] [-c chunk_size] [-k key] <file1> .. <fileN>\n", argv[0]); sol_quit_with_code(EXIT_FAILURE); return; } for (i = 1; i < argc; i++) { struct feed_ctx *ctx; struct sol_message_digest_config cfg = { SOL_SET_API_VERSION(.api_version = SOL_MESSAGE_DIGEST_CONFIG_API_VERSION, ) .algorithm = algorithm, .on_feed_done = on_feed_done, .on_digest_ready = on_digest_ready, }; struct sol_file_reader *fr; struct sol_blob *blob; struct sol_message_digest *mdh; int r; if (argv[i][0] == '-') { if (argv[i][1] == 'a') { if (i + 1 < argc) { algorithm = argv[i + 1]; i++; continue; } else fputs("ERROR: argument -a missing value.\n", stderr); } else if (argv[i][1] == 'k') { if (i + 1 < argc) { key = argv[i + 1]; i++; continue; } else fputs("ERROR: argument -a missing value.\n", stderr); } else if (argv[i][1] == 'c') { if (i + 1 < argc) { chunk_size = atoi(argv[i + 1]); i++; continue; } else fputs("ERROR: argument -c missing value.\n", stderr); } else fprintf(stderr, "ERROR: unknown option %s\n", argv[i]); sol_quit_with_code(EXIT_FAILURE); return; } fr = sol_file_reader_open(argv[i]); if (!fr) { fprintf(stderr, "ERROR: could not open file '%s': %s\n", argv[i], sol_util_strerrora(errno)); continue; } blob = sol_file_reader_to_blob(fr); if (!blob) { fprintf(stderr, "ERROR: could not create blob for file '%s'\n", argv[i]); continue; } cfg.data = ctx = calloc(1, sizeof(struct feed_ctx)); if (!ctx) { fprintf(stderr, "ERROR: could not allocate context memory " "to process file '%s'\n", argv[i]); sol_blob_unref(blob); continue; } ctx->file = argv[i]; ctx->start = sol_util_timespec_get_current(); ctx->done = 0; ctx->chunk_size = chunk_size; if (key) cfg.key = sol_str_slice_from_str(key); mdh = sol_message_digest_new(&cfg); if (!mdh) { fprintf(stderr, "ERROR: could not create message digest for " " algorithm \"%s\": %s\n", algorithm, sol_util_strerrora(errno)); sol_blob_unref(blob); free(ctx); continue; } if (chunk_size <= 0) { r = sol_message_digest_feed(mdh, blob, true); if (r < 0) { fprintf(stderr, "ERROR: could not feed message for " " algorithm \"%s\": %s\n", algorithm, sol_util_strerrora(-r)); sol_blob_unref(blob); sol_message_digest_del(mdh); free(ctx); continue; } } else { size_t offset = 0; while (offset < blob->size) { size_t remaining = blob->size - offset; size_t clen = remaining > chunk_size ? chunk_size : remaining; uint8_t *cmem = (uint8_t *)blob->mem + offset; bool is_last = offset + clen == blob->size; struct sol_blob *chunk = sol_blob_new(&SOL_BLOB_TYPE_NO_FREE_DATA, blob, cmem, clen); if (!chunk) { fprintf(stderr, "ERROR: could not create chunk blob at " "mem %p, size=%zd\n", cmem, clen); sol_blob_unref(blob); sol_message_digest_del(mdh); free(ctx); continue; } r = sol_message_digest_feed(mdh, chunk, is_last); if (r < 0) { fprintf(stderr, "ERROR: could not feed chunk for " " algorithm \"%s\": %s\n", algorithm, sol_util_strerrora(-r)); sol_blob_unref(blob); sol_blob_unref(chunk); sol_message_digest_del(mdh); free(ctx); continue; } sol_blob_unref(chunk); offset += clen; } } sol_blob_unref(blob); pending++; }