Delete unused files of thirparty libs (zlib, mbedtls)

Signed-off-by: Yevhen Babiichuk (DustDFG) <dfgdust@gmail.com>
This commit is contained in:
Yevhen Babiichuk (DustDFG) 2024-11-07 13:05:32 +02:00
parent 87318a2fb7
commit b607997bfc
10 changed files with 6 additions and 10033 deletions

View File

@ -556,8 +556,11 @@ File extracted from upstream release tarball:
- All `.h` from `include/mbedtls/` to `thirdparty/mbedtls/include/mbedtls/`
and all `.h` from `include/psa/` to `thirdparty/mbedtls/include/psa/`
- All `.c` and `.h` from `library/` to `thirdparty/mbedtls/library/` except
for the `psa_*.c` source files
- All `.c` and `.h` from `library/` to `thirdparty/mbedtls/library/`
- From `library/` to `thirdparty/mbedtls/library/`:
- All `.c` and `.h` files
- Except `bignum_mod.c`, `block_cipher.c`, `ecp_curves_new.c`, `lmots.c`,
`lms.c`
- The `LICENSE` file (edited to keep only the Apache 2.0 variant)
- Applied the patch `msvc-redeclaration-bug.diff` to fix a compilation error
with some MSVC versions
@ -1068,7 +1071,7 @@ Files extracted from upstream source:
Files extracted from upstream source:
- All `.c` and `.h` files, minus `infback.c`
- All `.c` and `.h` files, except `gz*.c` and `infback.c`
- `LICENSE`

View File

@ -1,394 +0,0 @@
/**
* Modular bignum functions
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#include "common.h"
#if defined(MBEDTLS_BIGNUM_C) && defined(MBEDTLS_ECP_WITH_MPI_UINT)
#include <string.h>
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include "mbedtls/bignum.h"
#include "mbedtls/platform.h"
#include "bignum_core.h"
#include "bignum_mod.h"
#include "bignum_mod_raw.h"
#include "constant_time_internal.h"
int mbedtls_mpi_mod_residue_setup(mbedtls_mpi_mod_residue *r,
const mbedtls_mpi_mod_modulus *N,
mbedtls_mpi_uint *p,
size_t p_limbs)
{
if (p_limbs != N->limbs || !mbedtls_mpi_core_lt_ct(p, N->p, N->limbs)) {
return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
}
r->limbs = N->limbs;
r->p = p;
return 0;
}
void mbedtls_mpi_mod_residue_release(mbedtls_mpi_mod_residue *r)
{
if (r == NULL) {
return;
}
r->limbs = 0;
r->p = NULL;
}
void mbedtls_mpi_mod_modulus_init(mbedtls_mpi_mod_modulus *N)
{
if (N == NULL) {
return;
}
N->p = NULL;
N->limbs = 0;
N->bits = 0;
N->int_rep = MBEDTLS_MPI_MOD_REP_INVALID;
}
void mbedtls_mpi_mod_modulus_free(mbedtls_mpi_mod_modulus *N)
{
if (N == NULL) {
return;
}
switch (N->int_rep) {
case MBEDTLS_MPI_MOD_REP_MONTGOMERY:
if (N->rep.mont.rr != NULL) {
mbedtls_zeroize_and_free((mbedtls_mpi_uint *) N->rep.mont.rr,
N->limbs * sizeof(mbedtls_mpi_uint));
N->rep.mont.rr = NULL;
}
N->rep.mont.mm = 0;
break;
case MBEDTLS_MPI_MOD_REP_OPT_RED:
N->rep.ored.modp = NULL;
break;
case MBEDTLS_MPI_MOD_REP_INVALID:
break;
}
N->p = NULL;
N->limbs = 0;
N->bits = 0;
N->int_rep = MBEDTLS_MPI_MOD_REP_INVALID;
}
static int set_mont_const_square(const mbedtls_mpi_uint **X,
const mbedtls_mpi_uint *A,
size_t limbs)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_mpi N;
mbedtls_mpi RR;
*X = NULL;
mbedtls_mpi_init(&N);
mbedtls_mpi_init(&RR);
if (A == NULL || limbs == 0 || limbs >= (MBEDTLS_MPI_MAX_LIMBS / 2) - 2) {
goto cleanup;
}
if (mbedtls_mpi_grow(&N, limbs)) {
goto cleanup;
}
memcpy(N.p, A, sizeof(mbedtls_mpi_uint) * limbs);
ret = mbedtls_mpi_core_get_mont_r2_unsafe(&RR, &N);
if (ret == 0) {
*X = RR.p;
RR.p = NULL;
}
cleanup:
mbedtls_mpi_free(&N);
mbedtls_mpi_free(&RR);
ret = (ret != 0) ? MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED : 0;
return ret;
}
static inline void standard_modulus_setup(mbedtls_mpi_mod_modulus *N,
const mbedtls_mpi_uint *p,
size_t p_limbs,
mbedtls_mpi_mod_rep_selector int_rep)
{
N->p = p;
N->limbs = p_limbs;
N->bits = mbedtls_mpi_core_bitlen(p, p_limbs);
N->int_rep = int_rep;
}
int mbedtls_mpi_mod_modulus_setup(mbedtls_mpi_mod_modulus *N,
const mbedtls_mpi_uint *p,
size_t p_limbs)
{
int ret = 0;
standard_modulus_setup(N, p, p_limbs, MBEDTLS_MPI_MOD_REP_MONTGOMERY);
N->rep.mont.mm = mbedtls_mpi_core_montmul_init(N->p);
ret = set_mont_const_square(&N->rep.mont.rr, N->p, N->limbs);
if (ret != 0) {
mbedtls_mpi_mod_modulus_free(N);
}
return ret;
}
int mbedtls_mpi_mod_optred_modulus_setup(mbedtls_mpi_mod_modulus *N,
const mbedtls_mpi_uint *p,
size_t p_limbs,
mbedtls_mpi_modp_fn modp)
{
standard_modulus_setup(N, p, p_limbs, MBEDTLS_MPI_MOD_REP_OPT_RED);
N->rep.ored.modp = modp;
return 0;
}
int mbedtls_mpi_mod_mul(mbedtls_mpi_mod_residue *X,
const mbedtls_mpi_mod_residue *A,
const mbedtls_mpi_mod_residue *B,
const mbedtls_mpi_mod_modulus *N)
{
if (N->limbs == 0) {
return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
}
if (X->limbs != N->limbs || A->limbs != N->limbs || B->limbs != N->limbs) {
return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
}
mbedtls_mpi_uint *T = mbedtls_calloc(N->limbs * 2 + 1, ciL);
if (T == NULL) {
return MBEDTLS_ERR_MPI_ALLOC_FAILED;
}
mbedtls_mpi_mod_raw_mul(X->p, A->p, B->p, N, T);
mbedtls_free(T);
return 0;
}
int mbedtls_mpi_mod_sub(mbedtls_mpi_mod_residue *X,
const mbedtls_mpi_mod_residue *A,
const mbedtls_mpi_mod_residue *B,
const mbedtls_mpi_mod_modulus *N)
{
if (X->limbs != N->limbs || A->limbs != N->limbs || B->limbs != N->limbs) {
return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
}
mbedtls_mpi_mod_raw_sub(X->p, A->p, B->p, N);
return 0;
}
static int mbedtls_mpi_mod_inv_mont(mbedtls_mpi_mod_residue *X,
const mbedtls_mpi_mod_residue *A,
const mbedtls_mpi_mod_modulus *N,
mbedtls_mpi_uint *working_memory)
{
/* Input already in Montgomery form, so there's little to do */
mbedtls_mpi_mod_raw_inv_prime(X->p, A->p,
N->p, N->limbs,
N->rep.mont.rr,
working_memory);
return 0;
}
static int mbedtls_mpi_mod_inv_non_mont(mbedtls_mpi_mod_residue *X,
const mbedtls_mpi_mod_residue *A,
const mbedtls_mpi_mod_modulus *N,
mbedtls_mpi_uint *working_memory)
{
/* Need to convert input into Montgomery form */
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_mpi_mod_modulus Nmont;
mbedtls_mpi_mod_modulus_init(&Nmont);
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_modulus_setup(&Nmont, N->p, N->limbs));
/* We'll use X->p to hold the Montgomery form of the input A->p */
mbedtls_mpi_core_to_mont_rep(X->p, A->p, Nmont.p, Nmont.limbs,
Nmont.rep.mont.mm, Nmont.rep.mont.rr,
working_memory);
mbedtls_mpi_mod_raw_inv_prime(X->p, X->p,
Nmont.p, Nmont.limbs,
Nmont.rep.mont.rr,
working_memory);
/* And convert back from Montgomery form */
mbedtls_mpi_core_from_mont_rep(X->p, X->p, Nmont.p, Nmont.limbs,
Nmont.rep.mont.mm, working_memory);
cleanup:
mbedtls_mpi_mod_modulus_free(&Nmont);
return ret;
}
int mbedtls_mpi_mod_inv(mbedtls_mpi_mod_residue *X,
const mbedtls_mpi_mod_residue *A,
const mbedtls_mpi_mod_modulus *N)
{
if (X->limbs != N->limbs || A->limbs != N->limbs) {
return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
}
/* Zero has the same value regardless of Montgomery form or not */
if (mbedtls_mpi_core_check_zero_ct(A->p, A->limbs) == 0) {
return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
}
size_t working_limbs =
mbedtls_mpi_mod_raw_inv_prime_working_limbs(N->limbs);
mbedtls_mpi_uint *working_memory = mbedtls_calloc(working_limbs,
sizeof(mbedtls_mpi_uint));
if (working_memory == NULL) {
return MBEDTLS_ERR_MPI_ALLOC_FAILED;
}
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
switch (N->int_rep) {
case MBEDTLS_MPI_MOD_REP_MONTGOMERY:
ret = mbedtls_mpi_mod_inv_mont(X, A, N, working_memory);
break;
case MBEDTLS_MPI_MOD_REP_OPT_RED:
ret = mbedtls_mpi_mod_inv_non_mont(X, A, N, working_memory);
break;
default:
ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
break;
}
mbedtls_zeroize_and_free(working_memory,
working_limbs * sizeof(mbedtls_mpi_uint));
return ret;
}
int mbedtls_mpi_mod_add(mbedtls_mpi_mod_residue *X,
const mbedtls_mpi_mod_residue *A,
const mbedtls_mpi_mod_residue *B,
const mbedtls_mpi_mod_modulus *N)
{
if (X->limbs != N->limbs || A->limbs != N->limbs || B->limbs != N->limbs) {
return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
}
mbedtls_mpi_mod_raw_add(X->p, A->p, B->p, N);
return 0;
}
int mbedtls_mpi_mod_random(mbedtls_mpi_mod_residue *X,
mbedtls_mpi_uint min,
const mbedtls_mpi_mod_modulus *N,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng)
{
if (X->limbs != N->limbs) {
return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
}
return mbedtls_mpi_mod_raw_random(X->p, min, N, f_rng, p_rng);
}
int mbedtls_mpi_mod_read(mbedtls_mpi_mod_residue *r,
const mbedtls_mpi_mod_modulus *N,
const unsigned char *buf,
size_t buflen,
mbedtls_mpi_mod_ext_rep ext_rep)
{
int ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
/* Do our best to check if r and m have been set up */
if (r->limbs == 0 || N->limbs == 0) {
goto cleanup;
}
if (r->limbs != N->limbs) {
goto cleanup;
}
ret = mbedtls_mpi_mod_raw_read(r->p, N, buf, buflen, ext_rep);
if (ret != 0) {
goto cleanup;
}
r->limbs = N->limbs;
ret = mbedtls_mpi_mod_raw_canonical_to_modulus_rep(r->p, N);
cleanup:
return ret;
}
int mbedtls_mpi_mod_write(const mbedtls_mpi_mod_residue *r,
const mbedtls_mpi_mod_modulus *N,
unsigned char *buf,
size_t buflen,
mbedtls_mpi_mod_ext_rep ext_rep)
{
/* Do our best to check if r and m have been set up */
if (r->limbs == 0 || N->limbs == 0) {
return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
}
if (r->limbs != N->limbs) {
return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
}
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_mpi_uint *working_memory = r->p;
size_t working_memory_len = sizeof(mbedtls_mpi_uint) * r->limbs;
if (N->int_rep == MBEDTLS_MPI_MOD_REP_MONTGOMERY) {
working_memory = mbedtls_calloc(r->limbs, sizeof(mbedtls_mpi_uint));
if (working_memory == NULL) {
ret = MBEDTLS_ERR_MPI_ALLOC_FAILED;
goto cleanup;
}
memcpy(working_memory, r->p, working_memory_len);
ret = mbedtls_mpi_mod_raw_from_mont_rep(working_memory, N);
if (ret != 0) {
goto cleanup;
}
}
ret = mbedtls_mpi_mod_raw_write(working_memory, N, buf, buflen, ext_rep);
cleanup:
if (N->int_rep == MBEDTLS_MPI_MOD_REP_MONTGOMERY &&
working_memory != NULL) {
mbedtls_zeroize_and_free(working_memory, working_memory_len);
}
return ret;
}
#endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ECP_WITH_MPI_UINT */

View File

@ -1,207 +0,0 @@
/**
* \file block_cipher.c
*
* \brief Lightweight abstraction layer for block ciphers with 128 bit blocks,
* for use by the GCM and CCM modules.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#include "common.h"
#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA)
#include "psa/crypto.h"
#include "psa_crypto_core.h"
#include "psa_util_internal.h"
#endif
#include "block_cipher_internal.h"
#if defined(MBEDTLS_BLOCK_CIPHER_C)
#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA)
static psa_key_type_t psa_key_type_from_block_cipher_id(mbedtls_block_cipher_id_t cipher_id)
{
switch (cipher_id) {
#if defined(MBEDTLS_BLOCK_CIPHER_AES_VIA_PSA)
case MBEDTLS_BLOCK_CIPHER_ID_AES:
return PSA_KEY_TYPE_AES;
#endif
#if defined(MBEDTLS_BLOCK_CIPHER_ARIA_VIA_PSA)
case MBEDTLS_BLOCK_CIPHER_ID_ARIA:
return PSA_KEY_TYPE_ARIA;
#endif
#if defined(MBEDTLS_BLOCK_CIPHER_CAMELLIA_VIA_PSA)
case MBEDTLS_BLOCK_CIPHER_ID_CAMELLIA:
return PSA_KEY_TYPE_CAMELLIA;
#endif
default:
return PSA_KEY_TYPE_NONE;
}
}
static int mbedtls_cipher_error_from_psa(psa_status_t status)
{
return PSA_TO_MBEDTLS_ERR_LIST(status, psa_to_cipher_errors,
psa_generic_status_to_mbedtls);
}
#endif /* MBEDTLS_BLOCK_CIPHER_SOME_PSA */
void mbedtls_block_cipher_free(mbedtls_block_cipher_context_t *ctx)
{
if (ctx == NULL) {
return;
}
#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA)
if (ctx->engine == MBEDTLS_BLOCK_CIPHER_ENGINE_PSA) {
psa_destroy_key(ctx->psa_key_id);
return;
}
#endif
switch (ctx->id) {
#if defined(MBEDTLS_AES_C)
case MBEDTLS_BLOCK_CIPHER_ID_AES:
mbedtls_aes_free(&ctx->ctx.aes);
break;
#endif
#if defined(MBEDTLS_ARIA_C)
case MBEDTLS_BLOCK_CIPHER_ID_ARIA:
mbedtls_aria_free(&ctx->ctx.aria);
break;
#endif
#if defined(MBEDTLS_CAMELLIA_C)
case MBEDTLS_BLOCK_CIPHER_ID_CAMELLIA:
mbedtls_camellia_free(&ctx->ctx.camellia);
break;
#endif
default:
break;
}
ctx->id = MBEDTLS_BLOCK_CIPHER_ID_NONE;
}
int mbedtls_block_cipher_setup(mbedtls_block_cipher_context_t *ctx,
mbedtls_cipher_id_t cipher_id)
{
ctx->id = (cipher_id == MBEDTLS_CIPHER_ID_AES) ? MBEDTLS_BLOCK_CIPHER_ID_AES :
(cipher_id == MBEDTLS_CIPHER_ID_ARIA) ? MBEDTLS_BLOCK_CIPHER_ID_ARIA :
(cipher_id == MBEDTLS_CIPHER_ID_CAMELLIA) ? MBEDTLS_BLOCK_CIPHER_ID_CAMELLIA :
MBEDTLS_BLOCK_CIPHER_ID_NONE;
#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA)
psa_key_type_t psa_key_type = psa_key_type_from_block_cipher_id(ctx->id);
if (psa_key_type != PSA_KEY_TYPE_NONE &&
psa_can_do_cipher(psa_key_type, PSA_ALG_ECB_NO_PADDING)) {
ctx->engine = MBEDTLS_BLOCK_CIPHER_ENGINE_PSA;
return 0;
}
ctx->engine = MBEDTLS_BLOCK_CIPHER_ENGINE_LEGACY;
#endif
switch (ctx->id) {
#if defined(MBEDTLS_AES_C)
case MBEDTLS_BLOCK_CIPHER_ID_AES:
mbedtls_aes_init(&ctx->ctx.aes);
return 0;
#endif
#if defined(MBEDTLS_ARIA_C)
case MBEDTLS_BLOCK_CIPHER_ID_ARIA:
mbedtls_aria_init(&ctx->ctx.aria);
return 0;
#endif
#if defined(MBEDTLS_CAMELLIA_C)
case MBEDTLS_BLOCK_CIPHER_ID_CAMELLIA:
mbedtls_camellia_init(&ctx->ctx.camellia);
return 0;
#endif
default:
ctx->id = MBEDTLS_BLOCK_CIPHER_ID_NONE;
return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
}
}
int mbedtls_block_cipher_setkey(mbedtls_block_cipher_context_t *ctx,
const unsigned char *key,
unsigned key_bitlen)
{
#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA)
if (ctx->engine == MBEDTLS_BLOCK_CIPHER_ENGINE_PSA) {
psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
psa_status_t status;
psa_set_key_type(&key_attr, psa_key_type_from_block_cipher_id(ctx->id));
psa_set_key_bits(&key_attr, key_bitlen);
psa_set_key_algorithm(&key_attr, PSA_ALG_ECB_NO_PADDING);
psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_ENCRYPT);
status = psa_import_key(&key_attr, key, PSA_BITS_TO_BYTES(key_bitlen), &ctx->psa_key_id);
if (status != PSA_SUCCESS) {
return mbedtls_cipher_error_from_psa(status);
}
psa_reset_key_attributes(&key_attr);
return 0;
}
#endif /* MBEDTLS_BLOCK_CIPHER_SOME_PSA */
switch (ctx->id) {
#if defined(MBEDTLS_AES_C)
case MBEDTLS_BLOCK_CIPHER_ID_AES:
return mbedtls_aes_setkey_enc(&ctx->ctx.aes, key, key_bitlen);
#endif
#if defined(MBEDTLS_ARIA_C)
case MBEDTLS_BLOCK_CIPHER_ID_ARIA:
return mbedtls_aria_setkey_enc(&ctx->ctx.aria, key, key_bitlen);
#endif
#if defined(MBEDTLS_CAMELLIA_C)
case MBEDTLS_BLOCK_CIPHER_ID_CAMELLIA:
return mbedtls_camellia_setkey_enc(&ctx->ctx.camellia, key, key_bitlen);
#endif
default:
return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT;
}
}
int mbedtls_block_cipher_encrypt(mbedtls_block_cipher_context_t *ctx,
const unsigned char input[16],
unsigned char output[16])
{
#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA)
if (ctx->engine == MBEDTLS_BLOCK_CIPHER_ENGINE_PSA) {
psa_status_t status;
size_t olen;
status = psa_cipher_encrypt(ctx->psa_key_id, PSA_ALG_ECB_NO_PADDING,
input, 16, output, 16, &olen);
if (status != PSA_SUCCESS) {
return mbedtls_cipher_error_from_psa(status);
}
return 0;
}
#endif /* MBEDTLS_BLOCK_CIPHER_SOME_PSA */
switch (ctx->id) {
#if defined(MBEDTLS_AES_C)
case MBEDTLS_BLOCK_CIPHER_ID_AES:
return mbedtls_aes_crypt_ecb(&ctx->ctx.aes, MBEDTLS_AES_ENCRYPT,
input, output);
#endif
#if defined(MBEDTLS_ARIA_C)
case MBEDTLS_BLOCK_CIPHER_ID_ARIA:
return mbedtls_aria_crypt_ecb(&ctx->ctx.aria, input, output);
#endif
#if defined(MBEDTLS_CAMELLIA_C)
case MBEDTLS_BLOCK_CIPHER_ID_CAMELLIA:
return mbedtls_camellia_crypt_ecb(&ctx->ctx.camellia,
MBEDTLS_CAMELLIA_ENCRYPT,
input, output);
#endif
default:
return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT;
}
}
#endif /* MBEDTLS_BLOCK_CIPHER_C */

File diff suppressed because it is too large Load Diff

View File

@ -1,786 +0,0 @@
/*
* The LM-OTS one-time public-key signature scheme
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
/*
* The following sources were referenced in the design of this implementation
* of the LM-OTS algorithm:
*
* [1] IETF RFC8554
* D. McGrew, M. Curcio, S.Fluhrer
* https://datatracker.ietf.org/doc/html/rfc8554
*
* [2] NIST Special Publication 800-208
* David A. Cooper et. al.
* https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-208.pdf
*/
#include "common.h"
#if defined(MBEDTLS_LMS_C)
#include <string.h>
#include "lmots.h"
#include "mbedtls/lms.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include "psa_util_internal.h"
#include "psa/crypto.h"
/* Define a local translating function to save code size by not using too many
* arguments in each translating place. */
static int local_err_translation(psa_status_t status)
{
return psa_status_to_mbedtls(status, psa_to_lms_errors,
ARRAY_LENGTH(psa_to_lms_errors),
psa_generic_status_to_mbedtls);
}
#define PSA_TO_MBEDTLS_ERR(status) local_err_translation(status)
#define PUBLIC_KEY_TYPE_OFFSET (0)
#define PUBLIC_KEY_I_KEY_ID_OFFSET (PUBLIC_KEY_TYPE_OFFSET + \
MBEDTLS_LMOTS_TYPE_LEN)
#define PUBLIC_KEY_Q_LEAF_ID_OFFSET (PUBLIC_KEY_I_KEY_ID_OFFSET + \
MBEDTLS_LMOTS_I_KEY_ID_LEN)
#define PUBLIC_KEY_KEY_HASH_OFFSET (PUBLIC_KEY_Q_LEAF_ID_OFFSET + \
MBEDTLS_LMOTS_Q_LEAF_ID_LEN)
/* We only support parameter sets that use 8-bit digits, as it does not require
* translation logic between digits and bytes */
#define W_WINTERNITZ_PARAMETER (8u)
#define CHECKSUM_LEN (2)
#define I_DIGIT_IDX_LEN (2)
#define J_HASH_IDX_LEN (1)
#define D_CONST_LEN (2)
#define DIGIT_MAX_VALUE ((1u << W_WINTERNITZ_PARAMETER) - 1u)
#define D_CONST_LEN (2)
static const unsigned char D_PUBLIC_CONSTANT_BYTES[D_CONST_LEN] = { 0x80, 0x80 };
static const unsigned char D_MESSAGE_CONSTANT_BYTES[D_CONST_LEN] = { 0x81, 0x81 };
#if defined(MBEDTLS_TEST_HOOKS)
int (*mbedtls_lmots_sign_private_key_invalidated_hook)(unsigned char *) = NULL;
#endif /* defined(MBEDTLS_TEST_HOOKS) */
/* Calculate the checksum digits that are appended to the end of the LMOTS digit
* string. See NIST SP800-208 section 3.1 or RFC8554 Algorithm 2 for details of
* the checksum algorithm.
*
* params The LMOTS parameter set, I and q values which
* describe the key being used.
*
* digest The digit string to create the digest from. As
* this does not contain a checksum, it is the same
* size as a hash output.
*/
static unsigned short lmots_checksum_calculate(const mbedtls_lmots_parameters_t *params,
const unsigned char *digest)
{
size_t idx;
unsigned sum = 0;
for (idx = 0; idx < MBEDTLS_LMOTS_N_HASH_LEN(params->type); idx++) {
sum += DIGIT_MAX_VALUE - digest[idx];
}
return sum;
}
/* Create the string of digest digits (in the base determined by the Winternitz
* parameter with the checksum appended to the end (Q || cksm(Q)). See NIST
* SP800-208 section 3.1 or RFC8554 Algorithm 3 step 5 (also used in Algorithm
* 4b step 3) for details.
*
* params The LMOTS parameter set, I and q values which
* describe the key being used.
*
* msg The message that will be hashed to create the
* digest.
*
* msg_size The size of the message.
*
* C_random_value The random value that will be combined with the
* message digest. This is always the same size as a
* hash output for whichever hash algorithm is
* determined by the parameter set.
*
* output An output containing the digit string (+
* checksum) of length P digits (in the case of
* MBEDTLS_LMOTS_SHA256_N32_W8, this means it is of
* size P bytes).
*/
static int create_digit_array_with_checksum(const mbedtls_lmots_parameters_t *params,
const unsigned char *msg,
size_t msg_len,
const unsigned char *C_random_value,
unsigned char *out)
{
psa_hash_operation_t op = PSA_HASH_OPERATION_INIT;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
size_t output_hash_len;
unsigned short checksum;
status = psa_hash_setup(&op, PSA_ALG_SHA_256);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, params->I_key_identifier,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, params->q_leaf_identifier,
MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, D_MESSAGE_CONSTANT_BYTES, D_CONST_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, C_random_value,
MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN(params->type));
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, msg, msg_len);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_finish(&op, out,
MBEDTLS_LMOTS_N_HASH_LEN(params->type),
&output_hash_len);
if (status != PSA_SUCCESS) {
goto exit;
}
checksum = lmots_checksum_calculate(params, out);
MBEDTLS_PUT_UINT16_BE(checksum, out, MBEDTLS_LMOTS_N_HASH_LEN(params->type));
exit:
psa_hash_abort(&op);
return PSA_TO_MBEDTLS_ERR(status);
}
/* Hash each element of the string of digits (+ checksum), producing a hash
* output for each element. This is used in several places (by varying the
* hash_idx_min/max_values) in order to calculate a public key from a private
* key (RFC8554 Algorithm 1 step 4), in order to sign a message (RFC8554
* Algorithm 3 step 5), and to calculate a public key candidate from a
* signature and message (RFC8554 Algorithm 4b step 3).
*
* params The LMOTS parameter set, I and q values which
* describe the key being used.
*
* x_digit_array The array of digits (of size P, 34 in the case of
* MBEDTLS_LMOTS_SHA256_N32_W8).
*
* hash_idx_min_values An array of the starting values of the j iterator
* for each of the members of the digit array. If
* this value in NULL, then all iterators will start
* at 0.
*
* hash_idx_max_values An array of the upper bound values of the j
* iterator for each of the members of the digit
* array. If this value in NULL, then iterator is
* bounded to be less than 2^w - 1 (255 in the case
* of MBEDTLS_LMOTS_SHA256_N32_W8)
*
* output An array containing a hash output for each member
* of the digit string P. In the case of
* MBEDTLS_LMOTS_SHA256_N32_W8, this is of size 32 *
* 34.
*/
static int hash_digit_array(const mbedtls_lmots_parameters_t *params,
const unsigned char *x_digit_array,
const unsigned char *hash_idx_min_values,
const unsigned char *hash_idx_max_values,
unsigned char *output)
{
unsigned int i_digit_idx;
unsigned char i_digit_idx_bytes[I_DIGIT_IDX_LEN];
unsigned int j_hash_idx;
unsigned char j_hash_idx_bytes[J_HASH_IDX_LEN];
unsigned int j_hash_idx_min;
unsigned int j_hash_idx_max;
psa_hash_operation_t op = PSA_HASH_OPERATION_INIT;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
size_t output_hash_len;
unsigned char tmp_hash[MBEDTLS_LMOTS_N_HASH_LEN_MAX];
for (i_digit_idx = 0;
i_digit_idx < MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(params->type);
i_digit_idx++) {
memcpy(tmp_hash,
&x_digit_array[i_digit_idx * MBEDTLS_LMOTS_N_HASH_LEN(params->type)],
MBEDTLS_LMOTS_N_HASH_LEN(params->type));
j_hash_idx_min = hash_idx_min_values != NULL ?
hash_idx_min_values[i_digit_idx] : 0;
j_hash_idx_max = hash_idx_max_values != NULL ?
hash_idx_max_values[i_digit_idx] : DIGIT_MAX_VALUE;
for (j_hash_idx = j_hash_idx_min;
j_hash_idx < j_hash_idx_max;
j_hash_idx++) {
status = psa_hash_setup(&op, PSA_ALG_SHA_256);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op,
params->I_key_identifier,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op,
params->q_leaf_identifier,
MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
MBEDTLS_PUT_UINT16_BE(i_digit_idx, i_digit_idx_bytes, 0);
status = psa_hash_update(&op, i_digit_idx_bytes, I_DIGIT_IDX_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
j_hash_idx_bytes[0] = (uint8_t) j_hash_idx;
status = psa_hash_update(&op, j_hash_idx_bytes, J_HASH_IDX_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, tmp_hash,
MBEDTLS_LMOTS_N_HASH_LEN(params->type));
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_finish(&op, tmp_hash, sizeof(tmp_hash),
&output_hash_len);
if (status != PSA_SUCCESS) {
goto exit;
}
psa_hash_abort(&op);
}
memcpy(&output[i_digit_idx * MBEDTLS_LMOTS_N_HASH_LEN(params->type)],
tmp_hash, MBEDTLS_LMOTS_N_HASH_LEN(params->type));
}
exit:
psa_hash_abort(&op);
mbedtls_platform_zeroize(tmp_hash, sizeof(tmp_hash));
return PSA_TO_MBEDTLS_ERR(status);
}
/* Combine the hashes of the digit array into a public key. This is used in
* in order to calculate a public key from a private key (RFC8554 Algorithm 1
* step 4), and to calculate a public key candidate from a signature and message
* (RFC8554 Algorithm 4b step 3).
*
* params The LMOTS parameter set, I and q values which describe
* the key being used.
* y_hashed_digits The array of hashes, one hash for each digit of the
* symbol array (which is of size P, 34 in the case of
* MBEDTLS_LMOTS_SHA256_N32_W8)
*
* pub_key The output public key (or candidate public key in
* case this is being run as part of signature
* verification), in the form of a hash output.
*/
static int public_key_from_hashed_digit_array(const mbedtls_lmots_parameters_t *params,
const unsigned char *y_hashed_digits,
unsigned char *pub_key)
{
psa_hash_operation_t op = PSA_HASH_OPERATION_INIT;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
size_t output_hash_len;
status = psa_hash_setup(&op, PSA_ALG_SHA_256);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op,
params->I_key_identifier,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, params->q_leaf_identifier,
MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, D_PUBLIC_CONSTANT_BYTES, D_CONST_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, y_hashed_digits,
MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(params->type) *
MBEDTLS_LMOTS_N_HASH_LEN(params->type));
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_finish(&op, pub_key,
MBEDTLS_LMOTS_N_HASH_LEN(params->type),
&output_hash_len);
if (status != PSA_SUCCESS) {
exit:
psa_hash_abort(&op);
}
return PSA_TO_MBEDTLS_ERR(status);
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
int mbedtls_lms_error_from_psa(psa_status_t status)
{
switch (status) {
case PSA_SUCCESS:
return 0;
case PSA_ERROR_HARDWARE_FAILURE:
return MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED;
case PSA_ERROR_NOT_SUPPORTED:
return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED;
case PSA_ERROR_BUFFER_TOO_SMALL:
return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
case PSA_ERROR_INVALID_ARGUMENT:
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
default:
return MBEDTLS_ERR_ERROR_GENERIC_ERROR;
}
}
#endif /* !MBEDTLS_DEPRECATED_REMOVED */
void mbedtls_lmots_public_init(mbedtls_lmots_public_t *ctx)
{
memset(ctx, 0, sizeof(*ctx));
}
void mbedtls_lmots_public_free(mbedtls_lmots_public_t *ctx)
{
if (ctx == NULL) {
return;
}
mbedtls_platform_zeroize(ctx, sizeof(*ctx));
}
int mbedtls_lmots_import_public_key(mbedtls_lmots_public_t *ctx,
const unsigned char *key, size_t key_len)
{
if (key_len < MBEDTLS_LMOTS_SIG_TYPE_OFFSET + MBEDTLS_LMOTS_TYPE_LEN) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
ctx->params.type = (mbedtls_lmots_algorithm_type_t)
MBEDTLS_GET_UINT32_BE(key, MBEDTLS_LMOTS_SIG_TYPE_OFFSET);
if (key_len != MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type)) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
memcpy(ctx->params.I_key_identifier,
key + PUBLIC_KEY_I_KEY_ID_OFFSET,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
memcpy(ctx->params.q_leaf_identifier,
key + PUBLIC_KEY_Q_LEAF_ID_OFFSET,
MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
memcpy(ctx->public_key,
key + PUBLIC_KEY_KEY_HASH_OFFSET,
MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type));
ctx->have_public_key = 1;
return 0;
}
int mbedtls_lmots_export_public_key(const mbedtls_lmots_public_t *ctx,
unsigned char *key, size_t key_size,
size_t *key_len)
{
if (key_size < MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type)) {
return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
}
if (!ctx->have_public_key) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
MBEDTLS_PUT_UINT32_BE(ctx->params.type, key, MBEDTLS_LMOTS_SIG_TYPE_OFFSET);
memcpy(key + PUBLIC_KEY_I_KEY_ID_OFFSET,
ctx->params.I_key_identifier,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
memcpy(key + PUBLIC_KEY_Q_LEAF_ID_OFFSET,
ctx->params.q_leaf_identifier,
MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
memcpy(key + PUBLIC_KEY_KEY_HASH_OFFSET, ctx->public_key,
MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type));
if (key_len != NULL) {
*key_len = MBEDTLS_LMOTS_PUBLIC_KEY_LEN(ctx->params.type);
}
return 0;
}
int mbedtls_lmots_calculate_public_key_candidate(const mbedtls_lmots_parameters_t *params,
const unsigned char *msg,
size_t msg_size,
const unsigned char *sig,
size_t sig_size,
unsigned char *out,
size_t out_size,
size_t *out_len)
{
unsigned char tmp_digit_array[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX];
unsigned char y_hashed_digits[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX];
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if (msg == NULL && msg_size != 0) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (sig_size != MBEDTLS_LMOTS_SIG_LEN(params->type) ||
out_size < MBEDTLS_LMOTS_N_HASH_LEN(params->type)) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
ret = create_digit_array_with_checksum(params, msg, msg_size,
sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET,
tmp_digit_array);
if (ret) {
return ret;
}
ret = hash_digit_array(params,
sig + MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET(params->type),
tmp_digit_array, NULL, (unsigned char *) y_hashed_digits);
if (ret) {
return ret;
}
ret = public_key_from_hashed_digit_array(params,
(unsigned char *) y_hashed_digits,
out);
if (ret) {
return ret;
}
if (out_len != NULL) {
*out_len = MBEDTLS_LMOTS_N_HASH_LEN(params->type);
}
return 0;
}
int mbedtls_lmots_verify(const mbedtls_lmots_public_t *ctx,
const unsigned char *msg, size_t msg_size,
const unsigned char *sig, size_t sig_size)
{
unsigned char Kc_public_key_candidate[MBEDTLS_LMOTS_N_HASH_LEN_MAX];
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if (msg == NULL && msg_size != 0) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (!ctx->have_public_key) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (ctx->params.type != MBEDTLS_LMOTS_SHA256_N32_W8) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (sig_size < MBEDTLS_LMOTS_SIG_TYPE_OFFSET + MBEDTLS_LMOTS_TYPE_LEN) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
if (MBEDTLS_GET_UINT32_BE(sig, MBEDTLS_LMOTS_SIG_TYPE_OFFSET) != MBEDTLS_LMOTS_SHA256_N32_W8) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
ret = mbedtls_lmots_calculate_public_key_candidate(&ctx->params,
msg, msg_size, sig, sig_size,
Kc_public_key_candidate,
MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type),
NULL);
if (ret) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
if (memcmp(&Kc_public_key_candidate, ctx->public_key,
sizeof(ctx->public_key))) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
return 0;
}
#if defined(MBEDTLS_LMS_PRIVATE)
void mbedtls_lmots_private_init(mbedtls_lmots_private_t *ctx)
{
memset(ctx, 0, sizeof(*ctx));
}
void mbedtls_lmots_private_free(mbedtls_lmots_private_t *ctx)
{
if (ctx == NULL) {
return;
}
mbedtls_platform_zeroize(ctx,
sizeof(*ctx));
}
int mbedtls_lmots_generate_private_key(mbedtls_lmots_private_t *ctx,
mbedtls_lmots_algorithm_type_t type,
const unsigned char I_key_identifier[MBEDTLS_LMOTS_I_KEY_ID_LEN],
uint32_t q_leaf_identifier,
const unsigned char *seed,
size_t seed_size)
{
psa_hash_operation_t op = PSA_HASH_OPERATION_INIT;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
size_t output_hash_len;
unsigned int i_digit_idx;
unsigned char i_digit_idx_bytes[2];
unsigned char const_bytes[1] = { 0xFF };
if (ctx->have_private_key) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (type != MBEDTLS_LMOTS_SHA256_N32_W8) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
ctx->params.type = type;
memcpy(ctx->params.I_key_identifier,
I_key_identifier,
sizeof(ctx->params.I_key_identifier));
MBEDTLS_PUT_UINT32_BE(q_leaf_identifier, ctx->params.q_leaf_identifier, 0);
for (i_digit_idx = 0;
i_digit_idx < MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(ctx->params.type);
i_digit_idx++) {
status = psa_hash_setup(&op, PSA_ALG_SHA_256);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op,
ctx->params.I_key_identifier,
sizeof(ctx->params.I_key_identifier));
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op,
ctx->params.q_leaf_identifier,
MBEDTLS_LMOTS_Q_LEAF_ID_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
MBEDTLS_PUT_UINT16_BE(i_digit_idx, i_digit_idx_bytes, 0);
status = psa_hash_update(&op, i_digit_idx_bytes, I_DIGIT_IDX_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, const_bytes, sizeof(const_bytes));
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, seed, seed_size);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_finish(&op,
ctx->private_key[i_digit_idx],
MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type),
&output_hash_len);
if (status != PSA_SUCCESS) {
goto exit;
}
psa_hash_abort(&op);
}
ctx->have_private_key = 1;
exit:
psa_hash_abort(&op);
return PSA_TO_MBEDTLS_ERR(status);
}
int mbedtls_lmots_calculate_public_key(mbedtls_lmots_public_t *ctx,
const mbedtls_lmots_private_t *priv_ctx)
{
unsigned char y_hashed_digits[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX];
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
/* Check that a private key is loaded */
if (!priv_ctx->have_private_key) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
ret = hash_digit_array(&priv_ctx->params,
(unsigned char *) priv_ctx->private_key, NULL,
NULL, (unsigned char *) y_hashed_digits);
if (ret) {
goto exit;
}
ret = public_key_from_hashed_digit_array(&priv_ctx->params,
(unsigned char *) y_hashed_digits,
ctx->public_key);
if (ret) {
goto exit;
}
memcpy(&ctx->params, &priv_ctx->params,
sizeof(ctx->params));
ctx->have_public_key = 1;
exit:
mbedtls_platform_zeroize(y_hashed_digits, sizeof(y_hashed_digits));
return ret;
}
int mbedtls_lmots_sign(mbedtls_lmots_private_t *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng, const unsigned char *msg, size_t msg_size,
unsigned char *sig, size_t sig_size, size_t *sig_len)
{
unsigned char tmp_digit_array[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX];
/* Create a temporary buffer to prepare the signature in. This allows us to
* finish creating a signature (ensuring the process doesn't fail), and then
* erase the private key **before** writing any data into the sig parameter
* buffer. If data were directly written into the sig buffer, it might leak
* a partial signature on failure, which effectively compromises the private
* key.
*/
unsigned char tmp_sig[MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT_MAX][MBEDTLS_LMOTS_N_HASH_LEN_MAX];
unsigned char tmp_c_random[MBEDTLS_LMOTS_N_HASH_LEN_MAX];
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if (msg == NULL && msg_size != 0) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (sig_size < MBEDTLS_LMOTS_SIG_LEN(ctx->params.type)) {
return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
}
/* Check that a private key is loaded */
if (!ctx->have_private_key) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
ret = f_rng(p_rng, tmp_c_random,
MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type));
if (ret) {
return ret;
}
ret = create_digit_array_with_checksum(&ctx->params,
msg, msg_size,
tmp_c_random,
tmp_digit_array);
if (ret) {
goto exit;
}
ret = hash_digit_array(&ctx->params, (unsigned char *) ctx->private_key,
NULL, tmp_digit_array, (unsigned char *) tmp_sig);
if (ret) {
goto exit;
}
MBEDTLS_PUT_UINT32_BE(ctx->params.type, sig, MBEDTLS_LMOTS_SIG_TYPE_OFFSET);
/* Test hook to check if sig is being written to before we invalidate the
* private key.
*/
#if defined(MBEDTLS_TEST_HOOKS)
if (mbedtls_lmots_sign_private_key_invalidated_hook != NULL) {
ret = (*mbedtls_lmots_sign_private_key_invalidated_hook)(sig);
if (ret != 0) {
return ret;
}
}
#endif /* defined(MBEDTLS_TEST_HOOKS) */
/* We've got a valid signature now, so it's time to make sure the private
* key can't be reused.
*/
ctx->have_private_key = 0;
mbedtls_platform_zeroize(ctx->private_key,
sizeof(ctx->private_key));
memcpy(sig + MBEDTLS_LMOTS_SIG_C_RANDOM_OFFSET, tmp_c_random,
MBEDTLS_LMOTS_C_RANDOM_VALUE_LEN(ctx->params.type));
memcpy(sig + MBEDTLS_LMOTS_SIG_SIGNATURE_OFFSET(ctx->params.type), tmp_sig,
MBEDTLS_LMOTS_P_SIG_DIGIT_COUNT(ctx->params.type)
* MBEDTLS_LMOTS_N_HASH_LEN(ctx->params.type));
if (sig_len != NULL) {
*sig_len = MBEDTLS_LMOTS_SIG_LEN(ctx->params.type);
}
ret = 0;
exit:
mbedtls_platform_zeroize(tmp_digit_array, sizeof(tmp_digit_array));
mbedtls_platform_zeroize(tmp_sig, sizeof(tmp_sig));
return ret;
}
#endif /* defined(MBEDTLS_LMS_PRIVATE) */
#endif /* defined(MBEDTLS_LMS_C) */

View File

@ -1,769 +0,0 @@
/*
* The LMS stateful-hash public-key signature scheme
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
/*
* The following sources were referenced in the design of this implementation
* of the LMS algorithm:
*
* [1] IETF RFC8554
* D. McGrew, M. Curcio, S.Fluhrer
* https://datatracker.ietf.org/doc/html/rfc8554
*
* [2] NIST Special Publication 800-208
* David A. Cooper et. al.
* https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-208.pdf
*/
#include "common.h"
#if defined(MBEDTLS_LMS_C)
#include <string.h>
#include "lmots.h"
#include "psa/crypto.h"
#include "psa_util_internal.h"
#include "mbedtls/lms.h"
#include "mbedtls/error.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/platform.h"
/* Define a local translating function to save code size by not using too many
* arguments in each translating place. */
static int local_err_translation(psa_status_t status)
{
return psa_status_to_mbedtls(status, psa_to_lms_errors,
ARRAY_LENGTH(psa_to_lms_errors),
psa_generic_status_to_mbedtls);
}
#define PSA_TO_MBEDTLS_ERR(status) local_err_translation(status)
#define SIG_Q_LEAF_ID_OFFSET (0)
#define SIG_OTS_SIG_OFFSET (SIG_Q_LEAF_ID_OFFSET + \
MBEDTLS_LMOTS_Q_LEAF_ID_LEN)
#define SIG_TYPE_OFFSET(otstype) (SIG_OTS_SIG_OFFSET + \
MBEDTLS_LMOTS_SIG_LEN(otstype))
#define SIG_PATH_OFFSET(otstype) (SIG_TYPE_OFFSET(otstype) + \
MBEDTLS_LMS_TYPE_LEN)
#define PUBLIC_KEY_TYPE_OFFSET (0)
#define PUBLIC_KEY_OTSTYPE_OFFSET (PUBLIC_KEY_TYPE_OFFSET + \
MBEDTLS_LMS_TYPE_LEN)
#define PUBLIC_KEY_I_KEY_ID_OFFSET (PUBLIC_KEY_OTSTYPE_OFFSET + \
MBEDTLS_LMOTS_TYPE_LEN)
#define PUBLIC_KEY_ROOT_NODE_OFFSET (PUBLIC_KEY_I_KEY_ID_OFFSET + \
MBEDTLS_LMOTS_I_KEY_ID_LEN)
/* Currently only support H=10 */
#define H_TREE_HEIGHT_MAX 10
#define MERKLE_TREE_NODE_AM(type) ((size_t) 1 << (MBEDTLS_LMS_H_TREE_HEIGHT(type) + 1u))
#define MERKLE_TREE_LEAF_NODE_AM(type) ((size_t) 1 << MBEDTLS_LMS_H_TREE_HEIGHT(type))
#define MERKLE_TREE_INTERNAL_NODE_AM(type) ((unsigned int) \
(1u << MBEDTLS_LMS_H_TREE_HEIGHT(type)))
#define D_CONST_LEN (2)
static const unsigned char D_LEAF_CONSTANT_BYTES[D_CONST_LEN] = { 0x82, 0x82 };
static const unsigned char D_INTR_CONSTANT_BYTES[D_CONST_LEN] = { 0x83, 0x83 };
/* Calculate the value of a leaf node of the Merkle tree (which is a hash of a
* public key and some other parameters like the leaf index). This function
* implements RFC8554 section 5.3, in the case where r >= 2^h.
*
* params The LMS parameter set, the underlying LMOTS
* parameter set, and I value which describe the key
* being used.
*
* pub_key The public key of the private whose index
* corresponds to the index of this leaf node. This
* is a hash output.
*
* r_node_idx The index of this node in the Merkle tree. Note
* that the root node of the Merkle tree is
* 1-indexed.
*
* out The output node value, which is a hash output.
*/
static int create_merkle_leaf_value(const mbedtls_lms_parameters_t *params,
unsigned char *pub_key,
unsigned int r_node_idx,
unsigned char *out)
{
psa_hash_operation_t op;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
size_t output_hash_len;
unsigned char r_node_idx_bytes[4];
op = psa_hash_operation_init();
status = psa_hash_setup(&op, PSA_ALG_SHA_256);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, params->I_key_identifier,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
MBEDTLS_PUT_UINT32_BE(r_node_idx, r_node_idx_bytes, 0);
status = psa_hash_update(&op, r_node_idx_bytes, 4);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, D_LEAF_CONSTANT_BYTES, D_CONST_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, pub_key,
MBEDTLS_LMOTS_N_HASH_LEN(params->otstype));
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_finish(&op, out, MBEDTLS_LMS_M_NODE_BYTES(params->type),
&output_hash_len);
if (status != PSA_SUCCESS) {
goto exit;
}
exit:
psa_hash_abort(&op);
return PSA_TO_MBEDTLS_ERR(status);
}
/* Calculate the value of an internal node of the Merkle tree (which is a hash
* of a public key and some other parameters like the node index). This function
* implements RFC8554 section 5.3, in the case where r < 2^h.
*
* params The LMS parameter set, the underlying LMOTS
* parameter set, and I value which describe the key
* being used.
*
* left_node The value of the child of this node which is on
* the left-hand side. As with all nodes on the
* Merkle tree, this is a hash output.
*
* right_node The value of the child of this node which is on
* the right-hand side. As with all nodes on the
* Merkle tree, this is a hash output.
*
* r_node_idx The index of this node in the Merkle tree. Note
* that the root node of the Merkle tree is
* 1-indexed.
*
* out The output node value, which is a hash output.
*/
static int create_merkle_internal_value(const mbedtls_lms_parameters_t *params,
const unsigned char *left_node,
const unsigned char *right_node,
unsigned int r_node_idx,
unsigned char *out)
{
psa_hash_operation_t op;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
size_t output_hash_len;
unsigned char r_node_idx_bytes[4];
op = psa_hash_operation_init();
status = psa_hash_setup(&op, PSA_ALG_SHA_256);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, params->I_key_identifier,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
MBEDTLS_PUT_UINT32_BE(r_node_idx, r_node_idx_bytes, 0);
status = psa_hash_update(&op, r_node_idx_bytes, 4);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, D_INTR_CONSTANT_BYTES, D_CONST_LEN);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, left_node,
MBEDTLS_LMS_M_NODE_BYTES(params->type));
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&op, right_node,
MBEDTLS_LMS_M_NODE_BYTES(params->type));
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_finish(&op, out, MBEDTLS_LMS_M_NODE_BYTES(params->type),
&output_hash_len);
if (status != PSA_SUCCESS) {
goto exit;
}
exit:
psa_hash_abort(&op);
return PSA_TO_MBEDTLS_ERR(status);
}
void mbedtls_lms_public_init(mbedtls_lms_public_t *ctx)
{
memset(ctx, 0, sizeof(*ctx));
}
void mbedtls_lms_public_free(mbedtls_lms_public_t *ctx)
{
if (ctx == NULL) {
return;
}
mbedtls_platform_zeroize(ctx, sizeof(*ctx));
}
int mbedtls_lms_import_public_key(mbedtls_lms_public_t *ctx,
const unsigned char *key, size_t key_size)
{
mbedtls_lms_algorithm_type_t type;
mbedtls_lmots_algorithm_type_t otstype;
type = (mbedtls_lms_algorithm_type_t) MBEDTLS_GET_UINT32_BE(key, PUBLIC_KEY_TYPE_OFFSET);
if (type != MBEDTLS_LMS_SHA256_M32_H10) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
ctx->params.type = type;
if (key_size != MBEDTLS_LMS_PUBLIC_KEY_LEN(ctx->params.type)) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
otstype = (mbedtls_lmots_algorithm_type_t)
MBEDTLS_GET_UINT32_BE(key, PUBLIC_KEY_OTSTYPE_OFFSET);
if (otstype != MBEDTLS_LMOTS_SHA256_N32_W8) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
ctx->params.otstype = otstype;
memcpy(ctx->params.I_key_identifier,
key + PUBLIC_KEY_I_KEY_ID_OFFSET,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
memcpy(ctx->T_1_pub_key, key + PUBLIC_KEY_ROOT_NODE_OFFSET,
MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type));
ctx->have_public_key = 1;
return 0;
}
int mbedtls_lms_export_public_key(const mbedtls_lms_public_t *ctx,
unsigned char *key,
size_t key_size, size_t *key_len)
{
if (key_size < MBEDTLS_LMS_PUBLIC_KEY_LEN(ctx->params.type)) {
return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
}
if (!ctx->have_public_key) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
MBEDTLS_PUT_UINT32_BE(ctx->params.type, key, PUBLIC_KEY_TYPE_OFFSET);
MBEDTLS_PUT_UINT32_BE(ctx->params.otstype, key, PUBLIC_KEY_OTSTYPE_OFFSET);
memcpy(key + PUBLIC_KEY_I_KEY_ID_OFFSET,
ctx->params.I_key_identifier,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
memcpy(key +PUBLIC_KEY_ROOT_NODE_OFFSET,
ctx->T_1_pub_key,
MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type));
if (key_len != NULL) {
*key_len = MBEDTLS_LMS_PUBLIC_KEY_LEN(ctx->params.type);
}
return 0;
}
int mbedtls_lms_verify(const mbedtls_lms_public_t *ctx,
const unsigned char *msg, size_t msg_size,
const unsigned char *sig, size_t sig_size)
{
unsigned int q_leaf_identifier;
unsigned char Kc_candidate_ots_pub_key[MBEDTLS_LMOTS_N_HASH_LEN_MAX];
unsigned char Tc_candidate_root_node[MBEDTLS_LMS_M_NODE_BYTES_MAX];
unsigned int height;
unsigned int curr_node_id;
unsigned int parent_node_id;
const unsigned char *left_node;
const unsigned char *right_node;
mbedtls_lmots_parameters_t ots_params;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if (!ctx->have_public_key) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (ctx->params.type
!= MBEDTLS_LMS_SHA256_M32_H10) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (ctx->params.otstype
!= MBEDTLS_LMOTS_SHA256_N32_W8) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (sig_size != MBEDTLS_LMS_SIG_LEN(ctx->params.type, ctx->params.otstype)) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
if (sig_size < SIG_OTS_SIG_OFFSET + MBEDTLS_LMOTS_TYPE_LEN) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
if (MBEDTLS_GET_UINT32_BE(sig, SIG_OTS_SIG_OFFSET + MBEDTLS_LMOTS_SIG_TYPE_OFFSET)
!= MBEDTLS_LMOTS_SHA256_N32_W8) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
if (sig_size < SIG_TYPE_OFFSET(ctx->params.otstype) + MBEDTLS_LMS_TYPE_LEN) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
if (MBEDTLS_GET_UINT32_BE(sig, SIG_TYPE_OFFSET(ctx->params.otstype))
!= MBEDTLS_LMS_SHA256_M32_H10) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
q_leaf_identifier = MBEDTLS_GET_UINT32_BE(sig, SIG_Q_LEAF_ID_OFFSET);
if (q_leaf_identifier >= MERKLE_TREE_LEAF_NODE_AM(ctx->params.type)) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
memcpy(ots_params.I_key_identifier,
ctx->params.I_key_identifier,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
MBEDTLS_PUT_UINT32_BE(q_leaf_identifier, ots_params.q_leaf_identifier, 0);
ots_params.type = ctx->params.otstype;
ret = mbedtls_lmots_calculate_public_key_candidate(&ots_params,
msg,
msg_size,
sig + SIG_OTS_SIG_OFFSET,
MBEDTLS_LMOTS_SIG_LEN(ctx->params.otstype),
Kc_candidate_ots_pub_key,
sizeof(Kc_candidate_ots_pub_key),
NULL);
if (ret != 0) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
create_merkle_leaf_value(
&ctx->params,
Kc_candidate_ots_pub_key,
MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) + q_leaf_identifier,
Tc_candidate_root_node);
curr_node_id = MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) +
q_leaf_identifier;
for (height = 0; height < MBEDTLS_LMS_H_TREE_HEIGHT(ctx->params.type);
height++) {
parent_node_id = curr_node_id / 2;
/* Left/right node ordering matters for the hash */
if (curr_node_id & 1) {
left_node = sig + SIG_PATH_OFFSET(ctx->params.otstype) +
height * MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type);
right_node = Tc_candidate_root_node;
} else {
left_node = Tc_candidate_root_node;
right_node = sig + SIG_PATH_OFFSET(ctx->params.otstype) +
height * MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type);
}
create_merkle_internal_value(&ctx->params, left_node, right_node,
parent_node_id, Tc_candidate_root_node);
curr_node_id /= 2;
}
if (memcmp(Tc_candidate_root_node, ctx->T_1_pub_key,
MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type))) {
return MBEDTLS_ERR_LMS_VERIFY_FAILED;
}
return 0;
}
#if defined(MBEDTLS_LMS_PRIVATE)
/* Calculate a full Merkle tree based on a private key. This function
* implements RFC8554 section 5.3, and is used to generate a public key (as the
* public key is the root node of the Merkle tree).
*
* ctx The LMS private context, containing a parameter
* set and private key material consisting of both
* public and private OTS.
*
* tree The output tree, which is 2^(H + 1) hash outputs.
* In the case of H=10 we have 2048 tree nodes (of
* which 1024 of them are leaf nodes). Note that
* because the Merkle tree root is 1-indexed, the 0
* index tree node is never used.
*/
static int calculate_merkle_tree(const mbedtls_lms_private_t *ctx,
unsigned char *tree)
{
unsigned int priv_key_idx;
unsigned int r_node_idx;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
/* First create the leaf nodes, in ascending order */
for (priv_key_idx = 0;
priv_key_idx < MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type);
priv_key_idx++) {
r_node_idx = MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) + priv_key_idx;
ret = create_merkle_leaf_value(&ctx->params,
ctx->ots_public_keys[priv_key_idx].public_key,
r_node_idx,
&tree[r_node_idx * MBEDTLS_LMS_M_NODE_BYTES(
ctx->params.type)]);
if (ret != 0) {
return ret;
}
}
/* Then the internal nodes, in reverse order so that we can guarantee the
* parent has been created */
for (r_node_idx = MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) - 1;
r_node_idx > 0;
r_node_idx--) {
ret = create_merkle_internal_value(&ctx->params,
&tree[(r_node_idx * 2) *
MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type)],
&tree[(r_node_idx * 2 + 1) *
MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type)],
r_node_idx,
&tree[r_node_idx *
MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type)]);
if (ret != 0) {
return ret;
}
}
return 0;
}
/* Calculate a path from a leaf node of the Merkle tree to the root of the tree,
* and return the full path. This function implements RFC8554 section 5.4.1, as
* the Merkle path is the main component of an LMS signature.
*
* ctx The LMS private context, containing a parameter
* set and private key material consisting of both
* public and private OTS.
*
* leaf_node_id Which leaf node to calculate the path from.
*
* path The output path, which is H hash outputs.
*/
static int get_merkle_path(mbedtls_lms_private_t *ctx,
unsigned int leaf_node_id,
unsigned char *path)
{
const size_t node_bytes = MBEDTLS_LMS_M_NODE_BYTES(ctx->params.type);
unsigned int curr_node_id = leaf_node_id;
unsigned int adjacent_node_id;
unsigned char *tree = NULL;
unsigned int height;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
tree = mbedtls_calloc((size_t) MERKLE_TREE_NODE_AM(ctx->params.type),
node_bytes);
if (tree == NULL) {
return MBEDTLS_ERR_LMS_ALLOC_FAILED;
}
ret = calculate_merkle_tree(ctx, tree);
if (ret != 0) {
goto exit;
}
for (height = 0; height < MBEDTLS_LMS_H_TREE_HEIGHT(ctx->params.type);
height++) {
adjacent_node_id = curr_node_id ^ 1;
memcpy(&path[height * node_bytes],
&tree[adjacent_node_id * node_bytes], node_bytes);
curr_node_id >>= 1;
}
ret = 0;
exit:
mbedtls_zeroize_and_free(tree, node_bytes *
(size_t) MERKLE_TREE_NODE_AM(ctx->params.type));
return ret;
}
void mbedtls_lms_private_init(mbedtls_lms_private_t *ctx)
{
memset(ctx, 0, sizeof(*ctx));
}
void mbedtls_lms_private_free(mbedtls_lms_private_t *ctx)
{
if (ctx == NULL) {
return;
}
unsigned int idx;
if (ctx->have_private_key) {
if (ctx->ots_private_keys != NULL) {
for (idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM(ctx->params.type); idx++) {
mbedtls_lmots_private_free(&ctx->ots_private_keys[idx]);
}
}
if (ctx->ots_public_keys != NULL) {
for (idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM(ctx->params.type); idx++) {
mbedtls_lmots_public_free(&ctx->ots_public_keys[idx]);
}
}
mbedtls_free(ctx->ots_private_keys);
mbedtls_free(ctx->ots_public_keys);
}
mbedtls_platform_zeroize(ctx, sizeof(*ctx));
}
int mbedtls_lms_generate_private_key(mbedtls_lms_private_t *ctx,
mbedtls_lms_algorithm_type_t type,
mbedtls_lmots_algorithm_type_t otstype,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng, const unsigned char *seed,
size_t seed_size)
{
unsigned int idx = 0;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if (type != MBEDTLS_LMS_SHA256_M32_H10) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (otstype != MBEDTLS_LMOTS_SHA256_N32_W8) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (ctx->have_private_key) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
ctx->params.type = type;
ctx->params.otstype = otstype;
ctx->have_private_key = 1;
ret = f_rng(p_rng,
ctx->params.I_key_identifier,
MBEDTLS_LMOTS_I_KEY_ID_LEN);
if (ret != 0) {
goto exit;
}
/* Requires a cast to size_t to avoid an implicit cast warning on certain
* platforms (particularly Windows) */
ctx->ots_private_keys = mbedtls_calloc((size_t) MERKLE_TREE_LEAF_NODE_AM(ctx->params.type),
sizeof(*ctx->ots_private_keys));
if (ctx->ots_private_keys == NULL) {
ret = MBEDTLS_ERR_LMS_ALLOC_FAILED;
goto exit;
}
/* Requires a cast to size_t to avoid an implicit cast warning on certain
* platforms (particularly Windows) */
ctx->ots_public_keys = mbedtls_calloc((size_t) MERKLE_TREE_LEAF_NODE_AM(ctx->params.type),
sizeof(*ctx->ots_public_keys));
if (ctx->ots_public_keys == NULL) {
ret = MBEDTLS_ERR_LMS_ALLOC_FAILED;
goto exit;
}
for (idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM(ctx->params.type); idx++) {
mbedtls_lmots_private_init(&ctx->ots_private_keys[idx]);
mbedtls_lmots_public_init(&ctx->ots_public_keys[idx]);
}
for (idx = 0; idx < MERKLE_TREE_LEAF_NODE_AM(ctx->params.type); idx++) {
ret = mbedtls_lmots_generate_private_key(&ctx->ots_private_keys[idx],
otstype,
ctx->params.I_key_identifier,
idx, seed, seed_size);
if (ret != 0) {
goto exit;
}
ret = mbedtls_lmots_calculate_public_key(&ctx->ots_public_keys[idx],
&ctx->ots_private_keys[idx]);
if (ret != 0) {
goto exit;
}
}
ctx->q_next_usable_key = 0;
exit:
if (ret != 0) {
mbedtls_lms_private_free(ctx);
}
return ret;
}
int mbedtls_lms_calculate_public_key(mbedtls_lms_public_t *ctx,
const mbedtls_lms_private_t *priv_ctx)
{
const size_t node_bytes = MBEDTLS_LMS_M_NODE_BYTES(priv_ctx->params.type);
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char *tree = NULL;
if (!priv_ctx->have_private_key) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (priv_ctx->params.type
!= MBEDTLS_LMS_SHA256_M32_H10) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (priv_ctx->params.otstype
!= MBEDTLS_LMOTS_SHA256_N32_W8) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
tree = mbedtls_calloc((size_t) MERKLE_TREE_NODE_AM(priv_ctx->params.type),
node_bytes);
if (tree == NULL) {
return MBEDTLS_ERR_LMS_ALLOC_FAILED;
}
memcpy(&ctx->params, &priv_ctx->params,
sizeof(mbedtls_lmots_parameters_t));
ret = calculate_merkle_tree(priv_ctx, tree);
if (ret != 0) {
goto exit;
}
/* Root node is always at position 1, due to 1-based indexing */
memcpy(ctx->T_1_pub_key, &tree[node_bytes], node_bytes);
ctx->have_public_key = 1;
ret = 0;
exit:
mbedtls_zeroize_and_free(tree, node_bytes *
(size_t) MERKLE_TREE_NODE_AM(priv_ctx->params.type));
return ret;
}
int mbedtls_lms_sign(mbedtls_lms_private_t *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng, const unsigned char *msg,
unsigned int msg_size, unsigned char *sig, size_t sig_size,
size_t *sig_len)
{
uint32_t q_leaf_identifier;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
if (!ctx->have_private_key) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (sig_size < MBEDTLS_LMS_SIG_LEN(ctx->params.type, ctx->params.otstype)) {
return MBEDTLS_ERR_LMS_BUFFER_TOO_SMALL;
}
if (ctx->params.type != MBEDTLS_LMS_SHA256_M32_H10) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (ctx->params.otstype
!= MBEDTLS_LMOTS_SHA256_N32_W8) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
if (ctx->q_next_usable_key >= MERKLE_TREE_LEAF_NODE_AM(ctx->params.type)) {
return MBEDTLS_ERR_LMS_OUT_OF_PRIVATE_KEYS;
}
q_leaf_identifier = ctx->q_next_usable_key;
/* This new value must _always_ be written back to the disk before the
* signature is returned.
*/
ctx->q_next_usable_key += 1;
if (MBEDTLS_LMS_SIG_LEN(ctx->params.type, ctx->params.otstype)
< SIG_OTS_SIG_OFFSET) {
return MBEDTLS_ERR_LMS_BAD_INPUT_DATA;
}
ret = mbedtls_lmots_sign(&ctx->ots_private_keys[q_leaf_identifier],
f_rng,
p_rng,
msg,
msg_size,
sig + SIG_OTS_SIG_OFFSET,
MBEDTLS_LMS_SIG_LEN(ctx->params.type,
ctx->params.otstype) - SIG_OTS_SIG_OFFSET,
NULL);
if (ret != 0) {
return ret;
}
MBEDTLS_PUT_UINT32_BE(ctx->params.type, sig, SIG_TYPE_OFFSET(ctx->params.otstype));
MBEDTLS_PUT_UINT32_BE(q_leaf_identifier, sig, SIG_Q_LEAF_ID_OFFSET);
ret = get_merkle_path(ctx,
MERKLE_TREE_INTERNAL_NODE_AM(ctx->params.type) + q_leaf_identifier,
sig + SIG_PATH_OFFSET(ctx->params.otstype));
if (ret != 0) {
return ret;
}
if (sig_len != NULL) {
*sig_len = MBEDTLS_LMS_SIG_LEN(ctx->params.type, ctx->params.otstype);
}
return 0;
}
#endif /* defined(MBEDTLS_LMS_PRIVATE) */
#endif /* defined(MBEDTLS_LMS_C) */

View File

@ -1,23 +0,0 @@
/* gzclose.c -- zlib gzclose() function
* Copyright (C) 2004, 2010 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "gzguts.h"
/* gzclose() is in a separate file so that it is linked in only if it is used.
That way the other gzclose functions can be used instead to avoid linking in
unneeded compression or decompression routines. */
int ZEXPORT gzclose(gzFile file) {
#ifndef NO_GZCOMPRESS
gz_statep state;
if (file == NULL)
return Z_STREAM_ERROR;
state = (gz_statep)file;
return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file);
#else
return gzclose_r(file);
#endif
}

View File

@ -1,582 +0,0 @@
/* gzlib.c -- zlib functions common to reading and writing gzip files
* Copyright (C) 2004-2024 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "gzguts.h"
#if defined(_WIN32) && !defined(__BORLANDC__)
# define LSEEK _lseeki64
#else
#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
# define LSEEK lseek64
#else
# define LSEEK lseek
#endif
#endif
#if defined UNDER_CE
/* Map the Windows error number in ERROR to a locale-dependent error message
string and return a pointer to it. Typically, the values for ERROR come
from GetLastError.
The string pointed to shall not be modified by the application, but may be
overwritten by a subsequent call to gz_strwinerror
The gz_strwinerror function does not change the current setting of
GetLastError. */
char ZLIB_INTERNAL *gz_strwinerror(DWORD error) {
static char buf[1024];
wchar_t *msgbuf;
DWORD lasterr = GetLastError();
DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL,
error,
0, /* Default language */
(LPVOID)&msgbuf,
0,
NULL);
if (chars != 0) {
/* If there is an \r\n appended, zap it. */
if (chars >= 2
&& msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
chars -= 2;
msgbuf[chars] = 0;
}
if (chars > sizeof (buf) - 1) {
chars = sizeof (buf) - 1;
msgbuf[chars] = 0;
}
wcstombs(buf, msgbuf, chars + 1);
LocalFree(msgbuf);
}
else {
sprintf(buf, "unknown win32 error (%ld)", error);
}
SetLastError(lasterr);
return buf;
}
#endif /* UNDER_CE */
/* Reset gzip file state */
local void gz_reset(gz_statep state) {
state->x.have = 0; /* no output data available */
if (state->mode == GZ_READ) { /* for reading ... */
state->eof = 0; /* not at end of file */
state->past = 0; /* have not read past end yet */
state->how = LOOK; /* look for gzip header */
}
else /* for writing ... */
state->reset = 0; /* no deflateReset pending */
state->seek = 0; /* no seek request pending */
gz_error(state, Z_OK, NULL); /* clear error */
state->x.pos = 0; /* no uncompressed data yet */
state->strm.avail_in = 0; /* no input data yet */
}
/* Open a gzip file either by name or file descriptor. */
local gzFile gz_open(const void *path, int fd, const char *mode) {
gz_statep state;
z_size_t len;
int oflag;
#ifdef O_CLOEXEC
int cloexec = 0;
#endif
#ifdef O_EXCL
int exclusive = 0;
#endif
/* check input */
if (path == NULL)
return NULL;
/* allocate gzFile structure to return */
state = (gz_statep)malloc(sizeof(gz_state));
if (state == NULL)
return NULL;
state->size = 0; /* no buffers allocated yet */
state->want = GZBUFSIZE; /* requested buffer size */
state->msg = NULL; /* no error message yet */
/* interpret mode */
state->mode = GZ_NONE;
state->level = Z_DEFAULT_COMPRESSION;
state->strategy = Z_DEFAULT_STRATEGY;
state->direct = 0;
while (*mode) {
if (*mode >= '0' && *mode <= '9')
state->level = *mode - '0';
else
switch (*mode) {
case 'r':
state->mode = GZ_READ;
break;
#ifndef NO_GZCOMPRESS
case 'w':
state->mode = GZ_WRITE;
break;
case 'a':
state->mode = GZ_APPEND;
break;
#endif
case '+': /* can't read and write at the same time */
free(state);
return NULL;
case 'b': /* ignore -- will request binary anyway */
break;
#ifdef O_CLOEXEC
case 'e':
cloexec = 1;
break;
#endif
#ifdef O_EXCL
case 'x':
exclusive = 1;
break;
#endif
case 'f':
state->strategy = Z_FILTERED;
break;
case 'h':
state->strategy = Z_HUFFMAN_ONLY;
break;
case 'R':
state->strategy = Z_RLE;
break;
case 'F':
state->strategy = Z_FIXED;
break;
case 'T':
state->direct = 1;
break;
default: /* could consider as an error, but just ignore */
;
}
mode++;
}
/* must provide an "r", "w", or "a" */
if (state->mode == GZ_NONE) {
free(state);
return NULL;
}
/* can't force transparent read */
if (state->mode == GZ_READ) {
if (state->direct) {
free(state);
return NULL;
}
state->direct = 1; /* for empty file */
}
/* save the path name for error messages */
#ifdef WIDECHAR
if (fd == -2) {
len = wcstombs(NULL, path, 0);
if (len == (z_size_t)-1)
len = 0;
}
else
#endif
len = strlen((const char *)path);
state->path = (char *)malloc(len + 1);
if (state->path == NULL) {
free(state);
return NULL;
}
#ifdef WIDECHAR
if (fd == -2)
if (len)
wcstombs(state->path, path, len + 1);
else
*(state->path) = 0;
else
#endif
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
(void)snprintf(state->path, len + 1, "%s", (const char *)path);
#else
strcpy(state->path, path);
#endif
/* compute the flags for open() */
oflag =
#ifdef O_LARGEFILE
O_LARGEFILE |
#endif
#ifdef O_BINARY
O_BINARY |
#endif
#ifdef O_CLOEXEC
(cloexec ? O_CLOEXEC : 0) |
#endif
(state->mode == GZ_READ ?
O_RDONLY :
(O_WRONLY | O_CREAT |
#ifdef O_EXCL
(exclusive ? O_EXCL : 0) |
#endif
(state->mode == GZ_WRITE ?
O_TRUNC :
O_APPEND)));
/* open the file with the appropriate flags (or just use fd) */
state->fd = fd > -1 ? fd : (
#ifdef WIDECHAR
fd == -2 ? _wopen(path, oflag, 0666) :
#endif
open((const char *)path, oflag, 0666));
if (state->fd == -1) {
free(state->path);
free(state);
return NULL;
}
if (state->mode == GZ_APPEND) {
LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */
state->mode = GZ_WRITE; /* simplify later checks */
}
/* save the current position for rewinding (only if reading) */
if (state->mode == GZ_READ) {
state->start = LSEEK(state->fd, 0, SEEK_CUR);
if (state->start == -1) state->start = 0;
}
/* initialize stream */
gz_reset(state);
/* return stream */
return (gzFile)state;
}
/* -- see zlib.h -- */
gzFile ZEXPORT gzopen(const char *path, const char *mode) {
return gz_open(path, -1, mode);
}
/* -- see zlib.h -- */
gzFile ZEXPORT gzopen64(const char *path, const char *mode) {
return gz_open(path, -1, mode);
}
/* -- see zlib.h -- */
gzFile ZEXPORT gzdopen(int fd, const char *mode) {
char *path; /* identifier for error messages */
gzFile gz;
if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
return NULL;
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
(void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd);
#else
sprintf(path, "<fd:%d>", fd); /* for debugging */
#endif
gz = gz_open(path, fd, mode);
free(path);
return gz;
}
/* -- see zlib.h -- */
#ifdef WIDECHAR
gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) {
return gz_open(path, -2, mode);
}
#endif
/* -- see zlib.h -- */
int ZEXPORT gzbuffer(gzFile file, unsigned size) {
gz_statep state;
/* get internal structure and check integrity */
if (file == NULL)
return -1;
state = (gz_statep)file;
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
return -1;
/* make sure we haven't already allocated memory */
if (state->size != 0)
return -1;
/* check and set requested size */
if ((size << 1) < size)
return -1; /* need to be able to double it */
if (size < 8)
size = 8; /* needed to behave well with flushing */
state->want = size;
return 0;
}
/* -- see zlib.h -- */
int ZEXPORT gzrewind(gzFile file) {
gz_statep state;
/* get internal structure */
if (file == NULL)
return -1;
state = (gz_statep)file;
/* check that we're reading and that there's no error */
if (state->mode != GZ_READ ||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
return -1;
/* back up and start over */
if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
return -1;
gz_reset(state);
return 0;
}
/* -- see zlib.h -- */
z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
unsigned n;
z_off64_t ret;
gz_statep state;
/* get internal structure and check integrity */
if (file == NULL)
return -1;
state = (gz_statep)file;
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
return -1;
/* check that there's no error */
if (state->err != Z_OK && state->err != Z_BUF_ERROR)
return -1;
/* can only seek from start or relative to current position */
if (whence != SEEK_SET && whence != SEEK_CUR)
return -1;
/* normalize offset to a SEEK_CUR specification */
if (whence == SEEK_SET)
offset -= state->x.pos;
else if (state->seek)
offset += state->skip;
state->seek = 0;
/* if within raw area while reading, just go there */
if (state->mode == GZ_READ && state->how == COPY &&
state->x.pos + offset >= 0) {
ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR);
if (ret == -1)
return -1;
state->x.have = 0;
state->eof = 0;
state->past = 0;
state->seek = 0;
gz_error(state, Z_OK, NULL);
state->strm.avail_in = 0;
state->x.pos += offset;
return state->x.pos;
}
/* calculate skip amount, rewinding if needed for back seek when reading */
if (offset < 0) {
if (state->mode != GZ_READ) /* writing -- can't go backwards */
return -1;
offset += state->x.pos;
if (offset < 0) /* before start of file! */
return -1;
if (gzrewind(file) == -1) /* rewind, then skip to offset */
return -1;
}
/* if reading, skip what's in output buffer (one less gzgetc() check) */
if (state->mode == GZ_READ) {
n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
(unsigned)offset : state->x.have;
state->x.have -= n;
state->x.next += n;
state->x.pos += n;
offset -= n;
}
/* request skip (if not zero) */
if (offset) {
state->seek = 1;
state->skip = offset;
}
return state->x.pos + offset;
}
/* -- see zlib.h -- */
z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
z_off64_t ret;
ret = gzseek64(file, (z_off64_t)offset, whence);
return ret == (z_off_t)ret ? (z_off_t)ret : -1;
}
/* -- see zlib.h -- */
z_off64_t ZEXPORT gztell64(gzFile file) {
gz_statep state;
/* get internal structure and check integrity */
if (file == NULL)
return -1;
state = (gz_statep)file;
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
return -1;
/* return position */
return state->x.pos + (state->seek ? state->skip : 0);
}
/* -- see zlib.h -- */
z_off_t ZEXPORT gztell(gzFile file) {
z_off64_t ret;
ret = gztell64(file);
return ret == (z_off_t)ret ? (z_off_t)ret : -1;
}
/* -- see zlib.h -- */
z_off64_t ZEXPORT gzoffset64(gzFile file) {
z_off64_t offset;
gz_statep state;
/* get internal structure and check integrity */
if (file == NULL)
return -1;
state = (gz_statep)file;
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
return -1;
/* compute and return effective offset in file */
offset = LSEEK(state->fd, 0, SEEK_CUR);
if (offset == -1)
return -1;
if (state->mode == GZ_READ) /* reading */
offset -= state->strm.avail_in; /* don't count buffered input */
return offset;
}
/* -- see zlib.h -- */
z_off_t ZEXPORT gzoffset(gzFile file) {
z_off64_t ret;
ret = gzoffset64(file);
return ret == (z_off_t)ret ? (z_off_t)ret : -1;
}
/* -- see zlib.h -- */
int ZEXPORT gzeof(gzFile file) {
gz_statep state;
/* get internal structure and check integrity */
if (file == NULL)
return 0;
state = (gz_statep)file;
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
return 0;
/* return end-of-file state */
return state->mode == GZ_READ ? state->past : 0;
}
/* -- see zlib.h -- */
const char * ZEXPORT gzerror(gzFile file, int *errnum) {
gz_statep state;
/* get internal structure and check integrity */
if (file == NULL)
return NULL;
state = (gz_statep)file;
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
return NULL;
/* return error information */
if (errnum != NULL)
*errnum = state->err;
return state->err == Z_MEM_ERROR ? "out of memory" :
(state->msg == NULL ? "" : state->msg);
}
/* -- see zlib.h -- */
void ZEXPORT gzclearerr(gzFile file) {
gz_statep state;
/* get internal structure and check integrity */
if (file == NULL)
return;
state = (gz_statep)file;
if (state->mode != GZ_READ && state->mode != GZ_WRITE)
return;
/* clear error and end-of-file */
if (state->mode == GZ_READ) {
state->eof = 0;
state->past = 0;
}
gz_error(state, Z_OK, NULL);
}
/* Create an error message in allocated memory and set state->err and
state->msg accordingly. Free any previous error message already there. Do
not try to free or allocate space if the error is Z_MEM_ERROR (out of
memory). Simply save the error message as a static string. If there is an
allocation failure constructing the error message, then convert the error to
out of memory. */
void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
/* free previously allocated message and clear */
if (state->msg != NULL) {
if (state->err != Z_MEM_ERROR)
free(state->msg);
state->msg = NULL;
}
/* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
if (err != Z_OK && err != Z_BUF_ERROR)
state->x.have = 0;
/* set error code, and if no message, then done */
state->err = err;
if (msg == NULL)
return;
/* for an out of memory error, return literal string when requested */
if (err == Z_MEM_ERROR)
return;
/* construct error message with path */
if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
NULL) {
state->err = Z_MEM_ERROR;
return;
}
#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
(void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
"%s%s%s", state->path, ": ", msg);
#else
strcpy(state->msg, state->path);
strcat(state->msg, ": ");
strcat(state->msg, msg);
#endif
}
/* portably return maximum value for an int (when limits.h presumed not
available) -- we need to do this to cover cases where 2's complement not
used, since C standard permits 1's complement and sign-bit representations,
otherwise we could just use ((unsigned)-1) >> 1 */
unsigned ZLIB_INTERNAL gz_intmax(void) {
#ifdef INT_MAX
return INT_MAX;
#else
unsigned p = 1, q;
do {
q = p;
p <<= 1;
p++;
} while (p > q);
return q >> 1;
#endif
}

View File

@ -1,602 +0,0 @@
/* gzread.c -- zlib functions for reading gzip files
* Copyright (C) 2004-2017 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "gzguts.h"
/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from
state->fd, and update state->eof, state->err, and state->msg as appropriate.
This function needs to loop on read(), since read() is not guaranteed to
read the number of bytes requested, depending on the type of descriptor. */
local int gz_load(gz_statep state, unsigned char *buf, unsigned len,
unsigned *have) {
int ret;
unsigned get, max = ((unsigned)-1 >> 2) + 1;
*have = 0;
do {
get = len - *have;
if (get > max)
get = max;
ret = read(state->fd, buf + *have, get);
if (ret <= 0)
break;
*have += (unsigned)ret;
} while (*have < len);
if (ret < 0) {
gz_error(state, Z_ERRNO, zstrerror());
return -1;
}
if (ret == 0)
state->eof = 1;
return 0;
}
/* Load up input buffer and set eof flag if last data loaded -- return -1 on
error, 0 otherwise. Note that the eof flag is set when the end of the input
file is reached, even though there may be unused data in the buffer. Once
that data has been used, no more attempts will be made to read the file.
If strm->avail_in != 0, then the current data is moved to the beginning of
the input buffer, and then the remainder of the buffer is loaded with the
available data from the input file. */
local int gz_avail(gz_statep state) {
unsigned got;
z_streamp strm = &(state->strm);
if (state->err != Z_OK && state->err != Z_BUF_ERROR)
return -1;
if (state->eof == 0) {
if (strm->avail_in) { /* copy what's there to the start */
unsigned char *p = state->in;
unsigned const char *q = strm->next_in;
unsigned n = strm->avail_in;
do {
*p++ = *q++;
} while (--n);
}
if (gz_load(state, state->in + strm->avail_in,
state->size - strm->avail_in, &got) == -1)
return -1;
strm->avail_in += got;
strm->next_in = state->in;
}
return 0;
}
/* Look for gzip header, set up for inflate or copy. state->x.have must be 0.
If this is the first time in, allocate required memory. state->how will be
left unchanged if there is no more input data available, will be set to COPY
if there is no gzip header and direct copying will be performed, or it will
be set to GZIP for decompression. If direct copying, then leftover input
data from the input buffer will be copied to the output buffer. In that
case, all further file reads will be directly to either the output buffer or
a user buffer. If decompressing, the inflate state will be initialized.
gz_look() will return 0 on success or -1 on failure. */
local int gz_look(gz_statep state) {
z_streamp strm = &(state->strm);
/* allocate read buffers and inflate memory */
if (state->size == 0) {
/* allocate buffers */
state->in = (unsigned char *)malloc(state->want);
state->out = (unsigned char *)malloc(state->want << 1);
if (state->in == NULL || state->out == NULL) {
free(state->out);
free(state->in);
gz_error(state, Z_MEM_ERROR, "out of memory");
return -1;
}
state->size = state->want;
/* allocate inflate memory */
state->strm.zalloc = Z_NULL;
state->strm.zfree = Z_NULL;
state->strm.opaque = Z_NULL;
state->strm.avail_in = 0;
state->strm.next_in = Z_NULL;
if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */
free(state->out);
free(state->in);
state->size = 0;
gz_error(state, Z_MEM_ERROR, "out of memory");
return -1;
}
}
/* get at least the magic bytes in the input buffer */
if (strm->avail_in < 2) {
if (gz_avail(state) == -1)
return -1;
if (strm->avail_in == 0)
return 0;
}
/* look for gzip magic bytes -- if there, do gzip decoding (note: there is
a logical dilemma here when considering the case of a partially written
gzip file, to wit, if a single 31 byte is written, then we cannot tell
whether this is a single-byte file, or just a partially written gzip
file -- for here we assume that if a gzip file is being written, then
the header will be written in a single operation, so that reading a
single byte is sufficient indication that it is not a gzip file) */
if (strm->avail_in > 1 &&
strm->next_in[0] == 31 && strm->next_in[1] == 139) {
inflateReset(strm);
state->how = GZIP;
state->direct = 0;
return 0;
}
/* no gzip header -- if we were decoding gzip before, then this is trailing
garbage. Ignore the trailing garbage and finish. */
if (state->direct == 0) {
strm->avail_in = 0;
state->eof = 1;
state->x.have = 0;
return 0;
}
/* doing raw i/o, copy any leftover input to output -- this assumes that
the output buffer is larger than the input buffer, which also assures
space for gzungetc() */
state->x.next = state->out;
memcpy(state->x.next, strm->next_in, strm->avail_in);
state->x.have = strm->avail_in;
strm->avail_in = 0;
state->how = COPY;
state->direct = 1;
return 0;
}
/* Decompress from input to the provided next_out and avail_out in the state.
On return, state->x.have and state->x.next point to the just decompressed
data. If the gzip stream completes, state->how is reset to LOOK to look for
the next gzip stream or raw data, once state->x.have is depleted. Returns 0
on success, -1 on failure. */
local int gz_decomp(gz_statep state) {
int ret = Z_OK;
unsigned had;
z_streamp strm = &(state->strm);
/* fill output buffer up to end of deflate stream */
had = strm->avail_out;
do {
/* get more input for inflate() */
if (strm->avail_in == 0 && gz_avail(state) == -1)
return -1;
if (strm->avail_in == 0) {
gz_error(state, Z_BUF_ERROR, "unexpected end of file");
break;
}
/* decompress and handle errors */
ret = inflate(strm, Z_NO_FLUSH);
if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
gz_error(state, Z_STREAM_ERROR,
"internal error: inflate stream corrupt");
return -1;
}
if (ret == Z_MEM_ERROR) {
gz_error(state, Z_MEM_ERROR, "out of memory");
return -1;
}
if (ret == Z_DATA_ERROR) { /* deflate stream invalid */
gz_error(state, Z_DATA_ERROR,
strm->msg == NULL ? "compressed data error" : strm->msg);
return -1;
}
} while (strm->avail_out && ret != Z_STREAM_END);
/* update available output */
state->x.have = had - strm->avail_out;
state->x.next = strm->next_out - state->x.have;
/* if the gzip stream completed successfully, look for another */
if (ret == Z_STREAM_END)
state->how = LOOK;
/* good decompression */
return 0;
}
/* Fetch data and put it in the output buffer. Assumes state->x.have is 0.
Data is either copied from the input file or decompressed from the input
file depending on state->how. If state->how is LOOK, then a gzip header is
looked for to determine whether to copy or decompress. Returns -1 on error,
otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the
end of the input file has been reached and all data has been processed. */
local int gz_fetch(gz_statep state) {
z_streamp strm = &(state->strm);
do {
switch(state->how) {
case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */
if (gz_look(state) == -1)
return -1;
if (state->how == LOOK)
return 0;
break;
case COPY: /* -> COPY */
if (gz_load(state, state->out, state->size << 1, &(state->x.have))
== -1)
return -1;
state->x.next = state->out;
return 0;
case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */
strm->avail_out = state->size << 1;
strm->next_out = state->out;
if (gz_decomp(state) == -1)
return -1;
}
} while (state->x.have == 0 && (!state->eof || strm->avail_in));
return 0;
}
/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */
local int gz_skip(gz_statep state, z_off64_t len) {
unsigned n;
/* skip over len bytes or reach end-of-file, whichever comes first */
while (len)
/* skip over whatever is in output buffer */
if (state->x.have) {
n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
(unsigned)len : state->x.have;
state->x.have -= n;
state->x.next += n;
state->x.pos += n;
len -= n;
}
/* output buffer empty -- return if we're at the end of the input */
else if (state->eof && state->strm.avail_in == 0)
break;
/* need more data to skip -- load up output buffer */
else {
/* get more output, looking for header if required */
if (gz_fetch(state) == -1)
return -1;
}
return 0;
}
/* Read len bytes into buf from file, or less than len up to the end of the
input. Return the number of bytes read. If zero is returned, either the
end of file was reached, or there was an error. state->err must be
consulted in that case to determine which. */
local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) {
z_size_t got;
unsigned n;
/* if len is zero, avoid unnecessary operations */
if (len == 0)
return 0;
/* process a skip request */
if (state->seek) {
state->seek = 0;
if (gz_skip(state, state->skip) == -1)
return 0;
}
/* get len bytes to buf, or less than len if at the end */
got = 0;
do {
/* set n to the maximum amount of len that fits in an unsigned int */
n = (unsigned)-1;
if (n > len)
n = (unsigned)len;
/* first just try copying data from the output buffer */
if (state->x.have) {
if (state->x.have < n)
n = state->x.have;
memcpy(buf, state->x.next, n);
state->x.next += n;
state->x.have -= n;
}
/* output buffer empty -- return if we're at the end of the input */
else if (state->eof && state->strm.avail_in == 0) {
state->past = 1; /* tried to read past end */
break;
}
/* need output data -- for small len or new stream load up our output
buffer */
else if (state->how == LOOK || n < (state->size << 1)) {
/* get more output, looking for header if required */
if (gz_fetch(state) == -1)
return 0;
continue; /* no progress yet -- go back to copy above */
/* the copy above assures that we will leave with space in the
output buffer, allowing at least one gzungetc() to succeed */
}
/* large len -- read directly into user buffer */
else if (state->how == COPY) { /* read directly */
if (gz_load(state, (unsigned char *)buf, n, &n) == -1)
return 0;
}
/* large len -- decompress directly into user buffer */
else { /* state->how == GZIP */
state->strm.avail_out = n;
state->strm.next_out = (unsigned char *)buf;
if (gz_decomp(state) == -1)
return 0;
n = state->x.have;
state->x.have = 0;
}
/* update progress */
len -= n;
buf = (char *)buf + n;
got += n;
state->x.pos += n;
} while (len);
/* return number of bytes read into user buffer */
return got;
}
/* -- see zlib.h -- */
int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) {
gz_statep state;
/* get internal structure */
if (file == NULL)
return -1;
state = (gz_statep)file;
/* check that we're reading and that there's no (serious) error */
if (state->mode != GZ_READ ||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
return -1;
/* since an int is returned, make sure len fits in one, otherwise return
with an error (this avoids a flaw in the interface) */
if ((int)len < 0) {
gz_error(state, Z_STREAM_ERROR, "request does not fit in an int");
return -1;
}
/* read len or fewer bytes to buf */
len = (unsigned)gz_read(state, buf, len);
/* check for an error */
if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR)
return -1;
/* return the number of bytes read (this is assured to fit in an int) */
return (int)len;
}
/* -- see zlib.h -- */
z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file) {
z_size_t len;
gz_statep state;
/* get internal structure */
if (file == NULL)
return 0;
state = (gz_statep)file;
/* check that we're reading and that there's no (serious) error */
if (state->mode != GZ_READ ||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
return 0;
/* compute bytes to read -- error on overflow */
len = nitems * size;
if (size && len / size != nitems) {
gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
return 0;
}
/* read len or fewer bytes to buf, return the number of full items read */
return len ? gz_read(state, buf, len) / size : 0;
}
/* -- see zlib.h -- */
#ifdef Z_PREFIX_SET
# undef z_gzgetc
#else
# undef gzgetc
#endif
int ZEXPORT gzgetc(gzFile file) {
unsigned char buf[1];
gz_statep state;
/* get internal structure */
if (file == NULL)
return -1;
state = (gz_statep)file;
/* check that we're reading and that there's no (serious) error */
if (state->mode != GZ_READ ||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
return -1;
/* try output buffer (no need to check for skip request) */
if (state->x.have) {
state->x.have--;
state->x.pos++;
return *(state->x.next)++;
}
/* nothing there -- try gz_read() */
return gz_read(state, buf, 1) < 1 ? -1 : buf[0];
}
int ZEXPORT gzgetc_(gzFile file) {
return gzgetc(file);
}
/* -- see zlib.h -- */
int ZEXPORT gzungetc(int c, gzFile file) {
gz_statep state;
/* get internal structure */
if (file == NULL)
return -1;
state = (gz_statep)file;
/* in case this was just opened, set up the input buffer */
if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
(void)gz_look(state);
/* check that we're reading and that there's no (serious) error */
if (state->mode != GZ_READ ||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
return -1;
/* process a skip request */
if (state->seek) {
state->seek = 0;
if (gz_skip(state, state->skip) == -1)
return -1;
}
/* can't push EOF */
if (c < 0)
return -1;
/* if output buffer empty, put byte at end (allows more pushing) */
if (state->x.have == 0) {
state->x.have = 1;
state->x.next = state->out + (state->size << 1) - 1;
state->x.next[0] = (unsigned char)c;
state->x.pos--;
state->past = 0;
return c;
}
/* if no room, give up (must have already done a gzungetc()) */
if (state->x.have == (state->size << 1)) {
gz_error(state, Z_DATA_ERROR, "out of room to push characters");
return -1;
}
/* slide output data if needed and insert byte before existing data */
if (state->x.next == state->out) {
unsigned char *src = state->out + state->x.have;
unsigned char *dest = state->out + (state->size << 1);
while (src > state->out)
*--dest = *--src;
state->x.next = dest;
}
state->x.have++;
state->x.next--;
state->x.next[0] = (unsigned char)c;
state->x.pos--;
state->past = 0;
return c;
}
/* -- see zlib.h -- */
char * ZEXPORT gzgets(gzFile file, char *buf, int len) {
unsigned left, n;
char *str;
unsigned char *eol;
gz_statep state;
/* check parameters and get internal structure */
if (file == NULL || buf == NULL || len < 1)
return NULL;
state = (gz_statep)file;
/* check that we're reading and that there's no (serious) error */
if (state->mode != GZ_READ ||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
return NULL;
/* process a skip request */
if (state->seek) {
state->seek = 0;
if (gz_skip(state, state->skip) == -1)
return NULL;
}
/* copy output bytes up to new line or len - 1, whichever comes first --
append a terminating zero to the string (we don't check for a zero in
the contents, let the user worry about that) */
str = buf;
left = (unsigned)len - 1;
if (left) do {
/* assure that something is in the output buffer */
if (state->x.have == 0 && gz_fetch(state) == -1)
return NULL; /* error */
if (state->x.have == 0) { /* end of file */
state->past = 1; /* read past end */
break; /* return what we have */
}
/* look for end-of-line in current output buffer */
n = state->x.have > left ? left : state->x.have;
eol = (unsigned char *)memchr(state->x.next, '\n', n);
if (eol != NULL)
n = (unsigned)(eol - state->x.next) + 1;
/* copy through end-of-line, or remainder if not found */
memcpy(buf, state->x.next, n);
state->x.have -= n;
state->x.next += n;
state->x.pos += n;
left -= n;
buf += n;
} while (left && eol == NULL);
/* return terminated string, or if nothing, end of file */
if (buf == str)
return NULL;
buf[0] = 0;
return str;
}
/* -- see zlib.h -- */
int ZEXPORT gzdirect(gzFile file) {
gz_statep state;
/* get internal structure */
if (file == NULL)
return 0;
state = (gz_statep)file;
/* if the state is not known, but we can find out, then do so (this is
mainly for right after a gzopen() or gzdopen()) */
if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
(void)gz_look(state);
/* return 1 if transparent, 0 if processing a gzip stream */
return state->direct;
}
/* -- see zlib.h -- */
int ZEXPORT gzclose_r(gzFile file) {
int ret, err;
gz_statep state;
/* get internal structure */
if (file == NULL)
return Z_STREAM_ERROR;
state = (gz_statep)file;
/* check that we're reading */
if (state->mode != GZ_READ)
return Z_STREAM_ERROR;
/* free memory and close file */
if (state->size) {
inflateEnd(&(state->strm));
free(state->out);
free(state->in);
}
err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
gz_error(state, Z_OK, NULL);
free(state->path);
ret = close(state->fd);
free(state);
return ret ? Z_ERRNO : err;
}

View File

@ -1,631 +0,0 @@
/* gzwrite.c -- zlib functions for writing gzip files
* Copyright (C) 2004-2019 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "gzguts.h"
/* Initialize state for writing a gzip file. Mark initialization by setting
state->size to non-zero. Return -1 on a memory allocation failure, or 0 on
success. */
local int gz_init(gz_statep state) {
int ret;
z_streamp strm = &(state->strm);
/* allocate input buffer (double size for gzprintf) */
state->in = (unsigned char *)malloc(state->want << 1);
if (state->in == NULL) {
gz_error(state, Z_MEM_ERROR, "out of memory");
return -1;
}
/* only need output buffer and deflate state if compressing */
if (!state->direct) {
/* allocate output buffer */
state->out = (unsigned char *)malloc(state->want);
if (state->out == NULL) {
free(state->in);
gz_error(state, Z_MEM_ERROR, "out of memory");
return -1;
}
/* allocate deflate memory, set up for gzip compression */
strm->zalloc = Z_NULL;
strm->zfree = Z_NULL;
strm->opaque = Z_NULL;
ret = deflateInit2(strm, state->level, Z_DEFLATED,
MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy);
if (ret != Z_OK) {
free(state->out);
free(state->in);
gz_error(state, Z_MEM_ERROR, "out of memory");
return -1;
}
strm->next_in = NULL;
}
/* mark state as initialized */
state->size = state->want;
/* initialize write buffer if compressing */
if (!state->direct) {
strm->avail_out = state->size;
strm->next_out = state->out;
state->x.next = strm->next_out;
}
return 0;
}
/* Compress whatever is at avail_in and next_in and write to the output file.
Return -1 if there is an error writing to the output file or if gz_init()
fails to allocate memory, otherwise 0. flush is assumed to be a valid
deflate() flush value. If flush is Z_FINISH, then the deflate() state is
reset to start a new gzip stream. If gz->direct is true, then simply write
to the output file without compressing, and ignore flush. */
local int gz_comp(gz_statep state, int flush) {
int ret, writ;
unsigned have, put, max = ((unsigned)-1 >> 2) + 1;
z_streamp strm = &(state->strm);
/* allocate memory if this is the first time through */
if (state->size == 0 && gz_init(state) == -1)
return -1;
/* write directly if requested */
if (state->direct) {
while (strm->avail_in) {
put = strm->avail_in > max ? max : strm->avail_in;
writ = write(state->fd, strm->next_in, put);
if (writ < 0) {
gz_error(state, Z_ERRNO, zstrerror());
return -1;
}
strm->avail_in -= (unsigned)writ;
strm->next_in += writ;
}
return 0;
}
/* check for a pending reset */
if (state->reset) {
/* don't start a new gzip member unless there is data to write */
if (strm->avail_in == 0)
return 0;
deflateReset(strm);
state->reset = 0;
}
/* run deflate() on provided input until it produces no more output */
ret = Z_OK;
do {
/* write out current buffer contents if full, or if flushing, but if
doing Z_FINISH then don't write until we get to Z_STREAM_END */
if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
(flush != Z_FINISH || ret == Z_STREAM_END))) {
while (strm->next_out > state->x.next) {
put = strm->next_out - state->x.next > (int)max ? max :
(unsigned)(strm->next_out - state->x.next);
writ = write(state->fd, state->x.next, put);
if (writ < 0) {
gz_error(state, Z_ERRNO, zstrerror());
return -1;
}
state->x.next += writ;
}
if (strm->avail_out == 0) {
strm->avail_out = state->size;
strm->next_out = state->out;
state->x.next = state->out;
}
}
/* compress */
have = strm->avail_out;
ret = deflate(strm, flush);
if (ret == Z_STREAM_ERROR) {
gz_error(state, Z_STREAM_ERROR,
"internal error: deflate stream corrupt");
return -1;
}
have -= strm->avail_out;
} while (have);
/* if that completed a deflate stream, allow another to start */
if (flush == Z_FINISH)
state->reset = 1;
/* all done, no errors */
return 0;
}
/* Compress len zeros to output. Return -1 on a write error or memory
allocation failure by gz_comp(), or 0 on success. */
local int gz_zero(gz_statep state, z_off64_t len) {
int first;
unsigned n;
z_streamp strm = &(state->strm);
/* consume whatever's left in the input buffer */
if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
return -1;
/* compress len zeros (len guaranteed > 0) */
first = 1;
while (len) {
n = GT_OFF(state->size) || (z_off64_t)state->size > len ?
(unsigned)len : state->size;
if (first) {
memset(state->in, 0, n);
first = 0;
}
strm->avail_in = n;
strm->next_in = state->in;
state->x.pos += n;
if (gz_comp(state, Z_NO_FLUSH) == -1)
return -1;
len -= n;
}
return 0;
}
/* Write len bytes from buf to file. Return the number of bytes written. If
the returned value is less than len, then there was an error. */
local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
z_size_t put = len;
/* if len is zero, avoid unnecessary operations */
if (len == 0)
return 0;
/* allocate memory if this is the first time through */
if (state->size == 0 && gz_init(state) == -1)
return 0;
/* check for seek request */
if (state->seek) {
state->seek = 0;
if (gz_zero(state, state->skip) == -1)
return 0;
}
/* for small len, copy to input buffer, otherwise compress directly */
if (len < state->size) {
/* copy to input buffer, compress when full */
do {
unsigned have, copy;
if (state->strm.avail_in == 0)
state->strm.next_in = state->in;
have = (unsigned)((state->strm.next_in + state->strm.avail_in) -
state->in);
copy = state->size - have;
if (copy > len)
copy = (unsigned)len;
memcpy(state->in + have, buf, copy);
state->strm.avail_in += copy;
state->x.pos += copy;
buf = (const char *)buf + copy;
len -= copy;
if (len && gz_comp(state, Z_NO_FLUSH) == -1)
return 0;
} while (len);
}
else {
/* consume whatever's left in the input buffer */
if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
return 0;
/* directly compress user buffer to file */
state->strm.next_in = (z_const Bytef *)buf;
do {
unsigned n = (unsigned)-1;
if (n > len)
n = (unsigned)len;
state->strm.avail_in = n;
state->x.pos += n;
if (gz_comp(state, Z_NO_FLUSH) == -1)
return 0;
len -= n;
} while (len);
}
/* input was all buffered or compressed */
return put;
}
/* -- see zlib.h -- */
int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) {
gz_statep state;
/* get internal structure */
if (file == NULL)
return 0;
state = (gz_statep)file;
/* check that we're writing and that there's no error */
if (state->mode != GZ_WRITE || state->err != Z_OK)
return 0;
/* since an int is returned, make sure len fits in one, otherwise return
with an error (this avoids a flaw in the interface) */
if ((int)len < 0) {
gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
return 0;
}
/* write len bytes from buf (the return value will fit in an int) */
return (int)gz_write(state, buf, len);
}
/* -- see zlib.h -- */
z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems,
gzFile file) {
z_size_t len;
gz_statep state;
/* get internal structure */
if (file == NULL)
return 0;
state = (gz_statep)file;
/* check that we're writing and that there's no error */
if (state->mode != GZ_WRITE || state->err != Z_OK)
return 0;
/* compute bytes to read -- error on overflow */
len = nitems * size;
if (size && len / size != nitems) {
gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
return 0;
}
/* write len bytes to buf, return the number of full items written */
return len ? gz_write(state, buf, len) / size : 0;
}
/* -- see zlib.h -- */
int ZEXPORT gzputc(gzFile file, int c) {
unsigned have;
unsigned char buf[1];
gz_statep state;
z_streamp strm;
/* get internal structure */
if (file == NULL)
return -1;
state = (gz_statep)file;
strm = &(state->strm);
/* check that we're writing and that there's no error */
if (state->mode != GZ_WRITE || state->err != Z_OK)
return -1;
/* check for seek request */
if (state->seek) {
state->seek = 0;
if (gz_zero(state, state->skip) == -1)
return -1;
}
/* try writing to input buffer for speed (state->size == 0 if buffer not
initialized) */
if (state->size) {
if (strm->avail_in == 0)
strm->next_in = state->in;
have = (unsigned)((strm->next_in + strm->avail_in) - state->in);
if (have < state->size) {
state->in[have] = (unsigned char)c;
strm->avail_in++;
state->x.pos++;
return c & 0xff;
}
}
/* no room in buffer or not initialized, use gz_write() */
buf[0] = (unsigned char)c;
if (gz_write(state, buf, 1) != 1)
return -1;
return c & 0xff;
}
/* -- see zlib.h -- */
int ZEXPORT gzputs(gzFile file, const char *s) {
z_size_t len, put;
gz_statep state;
/* get internal structure */
if (file == NULL)
return -1;
state = (gz_statep)file;
/* check that we're writing and that there's no error */
if (state->mode != GZ_WRITE || state->err != Z_OK)
return -1;
/* write string */
len = strlen(s);
if ((int)len < 0 || (unsigned)len != len) {
gz_error(state, Z_STREAM_ERROR, "string length does not fit in int");
return -1;
}
put = gz_write(state, s, len);
return put < len ? -1 : (int)len;
}
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#include <stdarg.h>
/* -- see zlib.h -- */
int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
int len;
unsigned left;
char *next;
gz_statep state;
z_streamp strm;
/* get internal structure */
if (file == NULL)
return Z_STREAM_ERROR;
state = (gz_statep)file;
strm = &(state->strm);
/* check that we're writing and that there's no error */
if (state->mode != GZ_WRITE || state->err != Z_OK)
return Z_STREAM_ERROR;
/* make sure we have some buffer space */
if (state->size == 0 && gz_init(state) == -1)
return state->err;
/* check for seek request */
if (state->seek) {
state->seek = 0;
if (gz_zero(state, state->skip) == -1)
return state->err;
}
/* do the printf() into the input buffer, put length in len -- the input
buffer is double-sized just for this function, so there is guaranteed to
be state->size bytes available after the current contents */
if (strm->avail_in == 0)
strm->next_in = state->in;
next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in);
next[state->size - 1] = 0;
#ifdef NO_vsnprintf
# ifdef HAS_vsprintf_void
(void)vsprintf(next, format, va);
for (len = 0; len < state->size; len++)
if (next[len] == 0) break;
# else
len = vsprintf(next, format, va);
# endif
#else
# ifdef HAS_vsnprintf_void
(void)vsnprintf(next, state->size, format, va);
len = strlen(next);
# else
len = vsnprintf(next, state->size, format, va);
# endif
#endif
/* check that printf() results fit in buffer */
if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0)
return 0;
/* update buffer and position, compress first half if past that */
strm->avail_in += (unsigned)len;
state->x.pos += len;
if (strm->avail_in >= state->size) {
left = strm->avail_in - state->size;
strm->avail_in = state->size;
if (gz_comp(state, Z_NO_FLUSH) == -1)
return state->err;
memmove(state->in, state->in + state->size, left);
strm->next_in = state->in;
strm->avail_in = left;
}
return len;
}
int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) {
va_list va;
int ret;
va_start(va, format);
ret = gzvprintf(file, format, va);
va_end(va);
return ret;
}
#else /* !STDC && !Z_HAVE_STDARG_H */
/* -- see zlib.h -- */
int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
int a4, int a5, int a6, int a7, int a8, int a9, int a10,
int a11, int a12, int a13, int a14, int a15, int a16,
int a17, int a18, int a19, int a20) {
unsigned len, left;
char *next;
gz_statep state;
z_streamp strm;
/* get internal structure */
if (file == NULL)
return Z_STREAM_ERROR;
state = (gz_statep)file;
strm = &(state->strm);
/* check that can really pass pointer in ints */
if (sizeof(int) != sizeof(void *))
return Z_STREAM_ERROR;
/* check that we're writing and that there's no error */
if (state->mode != GZ_WRITE || state->err != Z_OK)
return Z_STREAM_ERROR;
/* make sure we have some buffer space */
if (state->size == 0 && gz_init(state) == -1)
return state->error;
/* check for seek request */
if (state->seek) {
state->seek = 0;
if (gz_zero(state, state->skip) == -1)
return state->error;
}
/* do the printf() into the input buffer, put length in len -- the input
buffer is double-sized just for this function, so there is guaranteed to
be state->size bytes available after the current contents */
if (strm->avail_in == 0)
strm->next_in = state->in;
next = (char *)(strm->next_in + strm->avail_in);
next[state->size - 1] = 0;
#ifdef NO_snprintf
# ifdef HAS_sprintf_void
sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12,
a13, a14, a15, a16, a17, a18, a19, a20);
for (len = 0; len < size; len++)
if (next[len] == 0)
break;
# else
len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,
a12, a13, a14, a15, a16, a17, a18, a19, a20);
# endif
#else
# ifdef HAS_snprintf_void
snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9,
a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
len = strlen(next);
# else
len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8,
a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
# endif
#endif
/* check that printf() results fit in buffer */
if (len == 0 || len >= state->size || next[state->size - 1] != 0)
return 0;
/* update buffer and position, compress first half if past that */
strm->avail_in += len;
state->x.pos += len;
if (strm->avail_in >= state->size) {
left = strm->avail_in - state->size;
strm->avail_in = state->size;
if (gz_comp(state, Z_NO_FLUSH) == -1)
return state->err;
memmove(state->in, state->in + state->size, left);
strm->next_in = state->in;
strm->avail_in = left;
}
return (int)len;
}
#endif
/* -- see zlib.h -- */
int ZEXPORT gzflush(gzFile file, int flush) {
gz_statep state;
/* get internal structure */
if (file == NULL)
return Z_STREAM_ERROR;
state = (gz_statep)file;
/* check that we're writing and that there's no error */
if (state->mode != GZ_WRITE || state->err != Z_OK)
return Z_STREAM_ERROR;
/* check flush parameter */
if (flush < 0 || flush > Z_FINISH)
return Z_STREAM_ERROR;
/* check for seek request */
if (state->seek) {
state->seek = 0;
if (gz_zero(state, state->skip) == -1)
return state->err;
}
/* compress remaining data with requested flush */
(void)gz_comp(state, flush);
return state->err;
}
/* -- see zlib.h -- */
int ZEXPORT gzsetparams(gzFile file, int level, int strategy) {
gz_statep state;
z_streamp strm;
/* get internal structure */
if (file == NULL)
return Z_STREAM_ERROR;
state = (gz_statep)file;
strm = &(state->strm);
/* check that we're writing and that there's no error */
if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct)
return Z_STREAM_ERROR;
/* if no change is requested, then do nothing */
if (level == state->level && strategy == state->strategy)
return Z_OK;
/* check for seek request */
if (state->seek) {
state->seek = 0;
if (gz_zero(state, state->skip) == -1)
return state->err;
}
/* change compression parameters for subsequent input */
if (state->size) {
/* flush previous input with previous parameters before changing */
if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1)
return state->err;
deflateParams(strm, level, strategy);
}
state->level = level;
state->strategy = strategy;
return Z_OK;
}
/* -- see zlib.h -- */
int ZEXPORT gzclose_w(gzFile file) {
int ret = Z_OK;
gz_statep state;
/* get internal structure */
if (file == NULL)
return Z_STREAM_ERROR;
state = (gz_statep)file;
/* check that we're writing */
if (state->mode != GZ_WRITE)
return Z_STREAM_ERROR;
/* check for seek request */
if (state->seek) {
state->seek = 0;
if (gz_zero(state, state->skip) == -1)
ret = state->err;
}
/* flush, free memory, and close file */
if (gz_comp(state, Z_FINISH) == -1)
ret = state->err;
if (state->size) {
if (!state->direct) {
(void)deflateEnd(&(state->strm));
free(state->out);
}
free(state->in);
}
gz_error(state, Z_OK, NULL);
free(state->path);
if (close(state->fd) == -1)
ret = Z_ERRNO;
free(state);
return ret;
}