Skip to content

Commit 38cdb60

Browse files
committed
Add free() function to password_ctx
The user can now pass a `free()` function pointer that will be used to free the memory that has been allocated by the `callback()`. If `free()` is NULL, the library will still call `XFREE()`. Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
1 parent 056d0ba commit 38cdb60

File tree

15 files changed

+96
-68
lines changed

15 files changed

+96
-68
lines changed

helper.pl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ sub check_source {
4747
push @{$troubles->{unwanted_malloc}}, $lineno if $file =~ /^src\/.*\.c$/ && $l =~ /\bmalloc\s*\(/;
4848
push @{$troubles->{unwanted_realloc}}, $lineno if $file =~ /^src\/.*\.c$/ && $l =~ /\brealloc\s*\(/;
4949
push @{$troubles->{unwanted_calloc}}, $lineno if $file =~ /^src\/.*\.c$/ && $l =~ /\bcalloc\s*\(/;
50-
push @{$troubles->{unwanted_free}}, $lineno if $file =~ /^src\/.*\.c$/ && $l =~ /\bfree\s*\(/;
50+
push @{$troubles->{unwanted_free}}, $lineno if $file =~ /^src\/.*\.c$/ && $l =~ /[^>.]\bfree\s*\(/;
5151
push @{$troubles->{unwanted_memset}}, $lineno if $file =~ /^src\/.*\.c$/ && $l =~ /\bmemset\s*\(/;
5252
push @{$troubles->{unwanted_memcpy}}, $lineno if $file =~ /^src\/.*\.c$/ && $l =~ /\bmemcpy\s*\(/;
5353
push @{$troubles->{unwanted_memmove}}, $lineno if $file =~ /^src\/.*\.c$/ && $l =~ /\bmemmove\s*\(/;

src/headers/tomcrypt_pk.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
11
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
22
/* SPDX-License-Identifier: Unlicense */
33

4-
typedef struct {
4+
typedef struct password_ctx {
55
/**
66
Callback function that is called when a password is required.
77
88
Please be aware that the library takes ownership of the pointer that is
99
returned to the library via `str`.
10-
`str` shall be allocated via the same function as `XMALLOC` points to.
11-
The data will be zeroed and `XFREE`'d as soon as it isn't required anymore.
10+
The data will be zeroed and `free()`'d as soon as it isn't required anymore.
11+
c.f. the documentation of the `free()` function pointer for details.
1212
1313
@param str Pointer to pointer where the password will be stored.
1414
@param len Pointer to the length of the password.
1515
@param userdata `userdata` that was passed in the `password_ctx` struct.
1616
@return CRYPT_OK on success
1717
*/
1818
int (*callback)(void **str, unsigned long *len, void *userdata);
19+
/**
20+
Optional free function to free the allocated buffer.
21+
22+
At the point where the value returned by `callback()` is not required
23+
anymore the library will free it by either calling this `free()` function
24+
or `XFREE()` in case this `free()` function is set to `NULL`.
25+
26+
@param str Pointer to the buffer to be free'd.
27+
*/
28+
void (*free)(void *str);
1929
/** Opaque `userdata` pointer passed when the callback is called */
2030
void *userdata;
2131
} password_ctx;

src/headers/tomcrypt_private.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,16 @@ typedef struct {
6666
} ltc_dh_set_type;
6767

6868

69-
typedef int (*fn_kdf_t)(const unsigned char *password, unsigned long password_len,
70-
const unsigned char *salt, unsigned long salt_len,
69+
struct password {
70+
/* usually a `char*` but could also contain binary data
71+
* so use a `void*` + length to be on the safe side.
72+
*/
73+
void *pw;
74+
unsigned long l;
75+
};
76+
77+
typedef int (*fn_kdf_t)(const struct password *pwd,
78+
const unsigned char *salt, unsigned long salt_len,
7179
int iteration_count, int hash_idx,
7280
unsigned char *out, unsigned long *outlen);
7381

@@ -86,8 +94,7 @@ typedef struct {
8694
typedef struct
8795
{
8896
pbes_properties type;
89-
void *pwd;
90-
unsigned long pwdlen;
97+
struct password pw;
9198
ltc_asn1_list *enc_data;
9299
ltc_asn1_list *salt;
93100
ltc_asn1_list *iv;
@@ -259,14 +266,6 @@ enum cipher_mode {
259266
cm_none, cm_cbc, cm_cfb, cm_ctr, cm_ofb, cm_stream, cm_gcm
260267
};
261268

262-
struct password {
263-
/* usually a `char*` but could also contain binary data
264-
* so use a `void*` + length to be on the safe side.
265-
*/
266-
void *pw;
267-
unsigned long l;
268-
};
269-
270269
struct blockcipher_info {
271270
const char *name;
272271
const char *algo;
@@ -341,6 +340,7 @@ struct get_char {
341340
/* others */
342341

343342
void copy_or_zeromem(const unsigned char* src, unsigned char* dest, unsigned long len, int coz);
343+
void password_free(struct password *pw, const struct password_ctx *ctx);
344344

345345
int pbes_decrypt(const pbes_arg *arg, unsigned char *dec_data, unsigned long *dec_size);
346346

src/misc/password_free.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2+
/* SPDX-License-Identifier: Unlicense */
3+
#include "tomcrypt_private.h"
4+
5+
/**
6+
@file password_free.c
7+
Free the password inside a `struct password`, Steffen Jaeckel
8+
*/
9+
10+
/**
11+
Free a password
12+
@param pw The password to be free'd
13+
@param ctx The password context
14+
*/
15+
void password_free(struct password *pw, const struct password_ctx *ctx)
16+
{
17+
if (!ctx || !pw || !pw->pw)
18+
return;
19+
20+
zeromem(pw->pw, pw->l);
21+
if (ctx->free) {
22+
ctx->free(pw->pw);
23+
} else {
24+
XFREE(pw->pw);
25+
}
26+
pw->pw = NULL;
27+
pw->l = 0;
28+
}

src/misc/pbes/pbes.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ int pbes_decrypt(const pbes_arg *arg, unsigned char *dec_data, unsigned long *d
5050

5151
if (klen > sizeof(k)) return CRYPT_INVALID_ARG;
5252

53-
if ((err = arg->type.kdf(arg->pwd, arg->pwdlen, arg->salt->data, arg->salt->size, arg->iterations, hid, k, &klen)) != CRYPT_OK) goto LBL_ERROR;
53+
if ((err = arg->type.kdf(&arg->pw, arg->salt->data, arg->salt->size, arg->iterations, hid, k, &klen)) != CRYPT_OK) goto LBL_ERROR;
5454
if ((err = cbc_start(cid, iv, k, keylen, 0, &cbc)) != CRYPT_OK) goto LBL_ERROR;
5555
if ((err = cbc_decrypt(arg->enc_data->data, dec_data, arg->enc_data->size, &cbc)) != CRYPT_OK) goto LBL_ERROR;
5656
if ((err = cbc_done(&cbc)) != CRYPT_OK) goto LBL_ERROR;

src/misc/pbes/pbes1.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,28 @@
44

55
#ifdef LTC_PBES
66

7-
static int s_pkcs_5_alg1_wrap(const unsigned char *password, unsigned long password_len,
8-
const unsigned char *salt, unsigned long salt_len,
9-
int iteration_count, int hash_idx,
10-
unsigned char *out, unsigned long *outlen)
7+
static int s_pkcs_5_alg1_wrap(const struct password *pwd,
8+
const unsigned char *salt, unsigned long salt_len,
9+
int iteration_count, int hash_idx,
10+
unsigned char *out, unsigned long *outlen)
1111
{
1212
LTC_UNUSED_PARAM(salt_len);
13-
return pkcs_5_alg1(password, password_len, salt, iteration_count, hash_idx, out, outlen);
13+
return pkcs_5_alg1(pwd->pw, pwd->l, salt, iteration_count, hash_idx, out, outlen);
1414
}
1515

16-
static int s_pkcs_12_wrap(const unsigned char *password, unsigned long password_len,
17-
const unsigned char *salt, unsigned long salt_len,
18-
int iteration_count, int hash_idx,
19-
unsigned char *out, unsigned long *outlen)
16+
static int s_pkcs_12_wrap(const struct password *pwd,
17+
const unsigned char *salt, unsigned long salt_len,
18+
int iteration_count, int hash_idx,
19+
unsigned char *out, unsigned long *outlen)
2020
{
2121
int err;
2222
/* convert password to unicode/utf16-be */
23-
unsigned long pwlen = password_len * 2;
23+
unsigned long pwlen = pwd->l * 2;
2424
unsigned char* pw;
2525
if (*outlen < 32) return CRYPT_INVALID_ARG;
2626
pw = XMALLOC(pwlen + 2);
2727
if (pw == NULL) return CRYPT_MEM;
28-
if ((err = pkcs12_utf8_to_utf16(password, password_len, pw, &pwlen)) != CRYPT_OK) goto LBL_ERROR;
28+
if ((err = pkcs12_utf8_to_utf16(pwd->pw, pwd->l, pw, &pwlen)) != CRYPT_OK) goto LBL_ERROR;
2929
pw[pwlen++] = 0;
3030
pw[pwlen++] = 0;
3131
/* derive KEY */

src/misc/pbes/pbes2.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,21 @@ static const oid_id_st s_hmac_oid_names[] = {
2222
{ "1.2.840.113549.2.13", "sha512-256" },
2323
};
2424

25+
static int s_pkcs_5_alg2_wrap(const struct password *pwd,
26+
const unsigned char *salt, unsigned long salt_len,
27+
int iteration_count, int hash_idx,
28+
unsigned char *out, unsigned long *outlen)
29+
{
30+
return pkcs_5_alg2(pwd->pw, pwd->l, salt, salt_len, iteration_count, hash_idx, out, outlen);
31+
}
32+
2533
static const pbes_properties s_pbes2_default_types[] = {
26-
{ pkcs_5_alg2, "sha1", "des", 8, 0 },
27-
{ pkcs_5_alg2, "sha1", "rc2", 4, 0 },
28-
{ pkcs_5_alg2, "sha1", "3des", 24, 0 },
29-
{ pkcs_5_alg2, "sha1", "aes", 16, 0 },
30-
{ pkcs_5_alg2, "sha1", "aes", 24, 0 },
31-
{ pkcs_5_alg2, "sha1", "aes", 32, 0 },
34+
{ s_pkcs_5_alg2_wrap, "sha1", "des", 8, 0 },
35+
{ s_pkcs_5_alg2_wrap, "sha1", "rc2", 4, 0 },
36+
{ s_pkcs_5_alg2_wrap, "sha1", "3des", 24, 0 },
37+
{ s_pkcs_5_alg2_wrap, "sha1", "aes", 16, 0 },
38+
{ s_pkcs_5_alg2_wrap, "sha1", "aes", 24, 0 },
39+
{ s_pkcs_5_alg2_wrap, "sha1", "aes", 32, 0 },
3240
};
3341

3442
typedef struct {

src/misc/pem/pem_pkcs.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_c
202202
unsigned long w, l, n;
203203
int err = CRYPT_ERROR;
204204
struct pem_headers hdr = { 0 };
205-
struct password pw;
205+
struct password pw = { 0 };
206206
enum ltc_pka_id pka;
207207
XMEMSET(k, 0, sizeof(*k));
208208
w = LTC_PEM_READ_BUFSIZE * 2;
@@ -265,10 +265,7 @@ static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_c
265265
}
266266

267267
cleanup:
268-
if (hdr.pw) {
269-
zeromem(hdr.pw->pw, hdr.pw->l);
270-
XFREE(hdr.pw->pw);
271-
}
268+
password_free(hdr.pw, pw_ctx);
272269
XFREE(pem);
273270
return err;
274271
}

src/misc/pem/pem_ssh.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -589,9 +589,7 @@ static int s_decode_openssh(struct get_char *g, ltc_pka_key *k, const password_c
589589
}
590590

591591
cleanup:
592-
if (opts.pw.pw) {
593-
XFREE(opts.pw.pw);
594-
}
592+
password_free(&opts.pw, pw_ctx);
595593
if (privkey) {
596594
zeromem(privkey, privkey_len);
597595
XFREE(privkey);

src/pk/asn1/pkcs8/pkcs8_decode_flexi.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ int pkcs8_decode_flexi(const unsigned char *in, unsigned long inlen,
6363
goto LBL_DONE;
6464
}
6565

66-
if (pw_ctx->callback(&pbes.pwd, &pbes.pwdlen, pw_ctx->userdata)) {
66+
if (pw_ctx->callback(&pbes.pw.pw, &pbes.pw.l, pw_ctx->userdata)) {
6767
err = CRYPT_ERROR;
6868
goto LBL_DONE;
6969
}
@@ -94,15 +94,12 @@ int pkcs8_decode_flexi(const unsigned char *in, unsigned long inlen,
9494
}
9595

9696
LBL_DONE:
97-
if (l) der_free_sequence_flexi(l);
98-
if (pbes.pwd) {
99-
zeromem(pbes.pwd, pbes.pwdlen);
100-
XFREE(pbes.pwd);
101-
}
10297
if (dec_data) {
10398
zeromem(dec_data, dec_size);
10499
XFREE(dec_data);
105100
}
101+
password_free(&pbes.pw, pw_ctx);
102+
if (l) der_free_sequence_flexi(l);
106103
return err;
107104
}
108105

0 commit comments

Comments
 (0)