diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:33:12 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:33:12 +0000 |
commit | 36082a2fe36ecd800d784ae44c14f1f18c66a7e9 (patch) | |
tree | 6c68e0c0097987aff85a01dabddd34b862309a7c /lib/x509/pkcs12_encr.c | |
parent | Initial commit. (diff) | |
download | gnutls28-36082a2fe36ecd800d784ae44c14f1f18c66a7e9.tar.xz gnutls28-36082a2fe36ecd800d784ae44c14f1f18c66a7e9.zip |
Adding upstream version 3.7.9.upstream/3.7.9upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib/x509/pkcs12_encr.c')
-rw-r--r-- | lib/x509/pkcs12_encr.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/lib/x509/pkcs12_encr.c b/lib/x509/pkcs12_encr.c new file mode 100644 index 0000000..55c46e4 --- /dev/null +++ b/lib/x509/pkcs12_encr.c @@ -0,0 +1,227 @@ +/* minip12.c - A mini pkcs-12 implementation (modified for gnutls) + * + * Copyright (C) 2002-2012 Free Software Foundation, Inc. + * Copyright (C) 2017 Red Hat, Inc. + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + * + */ + +#include "gnutls_int.h" + +#include <mpi.h> +#include "errors.h" +#include <x509_int.h> +#include <algorithms.h> + +#define MAX_PASS_LEN 8192 +#define MAX_V_SIZE 128 +/* ID should be: + * 3 for MAC + * 2 for IV + * 1 for encryption key + * + * Note that this function produces different key for the + * NULL password, and for the password with zero length. + */ +int +_gnutls_pkcs12_string_to_key(const mac_entry_st * me, + unsigned int id, const uint8_t * salt, + unsigned int salt_size, unsigned int iter, + const char *pw, unsigned int req_keylen, + uint8_t * keybuf) +{ + int rc; + unsigned int i, j; + digest_hd_st md; + bigint_t num_b1 = NULL, num_ij = NULL; + bigint_t v_mpi = NULL; + unsigned int pwlen; + uint8_t hash[MAX_HASH_SIZE], buf_b[MAX_V_SIZE], buf_i[MAX_PASS_LEN + MAX_V_SIZE], *p; + uint8_t d[MAX_V_SIZE]; + size_t cur_keylen; + size_t n, m, plen, i_size; + size_t slen; + gnutls_datum_t ucs2 = {NULL, 0}; + unsigned mac_len; + uint8_t v_val[MAX_V_SIZE+1]; + unsigned v_size = 0; + + switch (me->id) { + case GNUTLS_DIG_GOSTR_94: + v_size = 32; + break; + case GNUTLS_DIG_SHA1: + case GNUTLS_DIG_SHA224: + case GNUTLS_DIG_SHA256: + case GNUTLS_DIG_STREEBOG_256: + case GNUTLS_DIG_STREEBOG_512: + v_size = 64; + break; + case GNUTLS_DIG_SHA384: + case GNUTLS_DIG_SHA512: + v_size = 128; + break; + default: + break; + } + + if (v_size == 0 || v_size > MAX_V_SIZE) + return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); + + memset(v_val, 0, sizeof(v_val)); + v_val[0] = 0x01; /* make it be 2^64 or 2^128 */ + + cur_keylen = 0; + + if (pw) { + pwlen = strlen(pw); + + if (pwlen == 0) { + ucs2.data = gnutls_calloc(1, 2); + if (ucs2.data == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + ucs2.size = 2; + } else { + rc = _gnutls_utf8_to_ucs2(pw, pwlen, &ucs2, 1); + if (rc < 0) + return gnutls_assert_val(rc); + + /* include terminating zero */ + ucs2.size+=2; + } + pwlen = ucs2.size; + pw = (char*)ucs2.data; + } else { + pwlen = 0; + } + + if (pwlen > MAX_PASS_LEN) { + rc = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + goto cleanup; + } + + rc = _gnutls_mpi_init_scan(&v_mpi, v_val, v_size+1); + if (rc < 0) { + gnutls_assert(); + goto cleanup; + } + + /* Store salt and password in BUF_I */ + slen = ((salt_size+v_size-1)/v_size) * v_size; + plen = ((pwlen+v_size-1)/v_size) * v_size; + i_size = slen + plen; + + if (i_size > sizeof(buf_i)) { + rc = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + goto cleanup; + } + + p = buf_i; + for (i = 0; i < slen; i++) + *p++ = salt[i % salt_size]; + + if (pw) { + for (i = j = 0; i < plen; i += 2) { + *p++ = pw[j]; + *p++ = pw[j+1]; + j+=2; + if (j >= pwlen) + j = 0; + } + } else { + memset(p, 0, plen); + } + + mac_len = _gnutls_mac_get_algo_len(me); + assert(mac_len != 0); + + for (;;) { + rc = _gnutls_hash_init(&md, me); + if (rc < 0) { + gnutls_assert(); + goto cleanup; + } + memset(d, id & 0xff, v_size); + _gnutls_hash(&md, d, v_size); + _gnutls_hash(&md, buf_i, i_size); + _gnutls_hash_deinit(&md, hash); + for (i = 1; i < iter; i++) { + rc = _gnutls_hash_fast((gnutls_digest_algorithm_t)me->id, + hash, mac_len, hash); + if (rc < 0) { + gnutls_assert(); + goto cleanup; + } + } + for (i = 0; i < mac_len && cur_keylen < req_keylen; i++) + keybuf[cur_keylen++] = hash[i]; + if (cur_keylen == req_keylen) { + rc = 0; /* ready */ + goto cleanup; + } + + /* need more bytes. */ + for (i = 0; i < v_size; i++) + buf_b[i] = hash[i % mac_len]; + n = v_size; + rc = _gnutls_mpi_init_scan(&num_b1, buf_b, n); + if (rc < 0) { + gnutls_assert(); + goto cleanup; + } + + rc = _gnutls_mpi_add_ui(num_b1, num_b1, 1); + if (rc < 0) { + gnutls_assert(); + goto cleanup; + } + + for (i = 0; i < i_size; i += v_size) { + n = v_size; + rc = _gnutls_mpi_init_scan(&num_ij, buf_i + i, n); + if (rc < 0) { + gnutls_assert(); + goto cleanup; + } + + rc = _gnutls_mpi_addm(num_ij, num_ij, num_b1, v_mpi); + if (rc < 0) { + gnutls_assert(); + goto cleanup; + } + + n = v_size; + m = (_gnutls_mpi_get_nbits(num_ij) + 7) / 8; + + memset(buf_i + i, 0, n - m); + rc = _gnutls_mpi_print(num_ij, buf_i + i + n - m, + &n); + if (rc < 0) { + gnutls_assert(); + goto cleanup; + } + _gnutls_mpi_release(&num_ij); + } + } + cleanup: + _gnutls_mpi_release(&num_ij); + _gnutls_mpi_release(&num_b1); + _gnutls_mpi_release(&v_mpi); + gnutls_free(ucs2.data); + + return rc; +} |