After CRYPTO_secure_malloc_init OpenSSL will automatically store private
keys in secure heap. OPENSSL_secure_malloc(3):
If a secure heap is used, then private key BIGNUM values are stored
there. This protects long-term storage of private keys, but will not
necessarily put all intermediate values and computations there.
Additionally, we try to keep user passwords in secure heap too.
This facility is only available since OpenSSL_1_1_0-pre1.
Signed-off-by: Vitaly Chikunov <redacted>
Reviewed-by: Bruno Meneguele <redacted>
Cc: Stefan Berger <stefanb@linux.ibm.com>
---
Change since v3:
- Undo secure heap handling from (file2bin and) calc_evm_hmac since this
is debugging tool only. Add comment about this.
- Since there is only code removals and new comments I keep Reviewed-by
tag.
src/evmctl.c | 97 +++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 85 insertions(+), 12 deletions(-)
@@ -165,6 +166,24 @@ struct tpm_bank_info {staticchar*pcrfile[MAX_PCRFILE];staticunsignednpcrfile;+#if OPENSSL_VERSION_NUMBER <= 0x10100000+#warning Your OpenSSL version is too old to have OPENSSL_secure_malloc, \+fallingbacktouseplainOPENSSL_malloc.+#define OPENSSL_secure_malloc OPENSSL_malloc+#define OPENSSL_secure_free OPENSSL_free+/*+*Secureheapmemoryautomaticallyclearedonfree,but+*OPENSSL_secure_clear_freewillbeusedincaseoffallback+*toplainOPENSSL_malloc.+*/+#define OPENSSL_secure_clear_free OPENSSL_clear_free+#define OPENSSL_clear_free(ptr, num) \+do{\+OPENSSL_cleanse(ptr,num);\+OPENSSL_free(ptr);\+}while(0)+#endif+staticintbin2file(constchar*file,constchar*ext,constunsignedchar*data,intlen){FILE*fp;
@@ -1072,6 +1091,7 @@ static int cmd_setxattr_ima(struct command *cmd)#define MAX_KEY_SIZE 128+/* This function is debugging tool and should not be used for real private data. */staticintcalc_evm_hmac(constchar*file,constchar*keyfile,unsignedchar*hash){constEVP_MD*md;
@@ -2596,15 +2616,41 @@ static struct option opts[] = {};+/*+*Copypasswordfromoptargintosecureheap,soitcouldbe+*freedinthesamewayasaresultofget_password().+*/+staticchar*optarg_password(char*optarg)+{+size_tlen;+char*keypass;++if(!optarg)+returnNULL;+len=strlen(optarg);+keypass=OPENSSL_secure_malloc(len+1);+if(keypass)+memcpy(keypass,optarg,len+1);+else+log_err("OPENSSL_secure_malloc(%zu) failed\n",len+1);+/*+*Thismemsetdoesnotaddrealsecurity,justincreases+*thechanceofpasswordbeingobscuredinpsoutput.+*/+memset(optarg,'X',len);+returnkeypass;+}++/* Read from TTY into secure heap. */staticchar*get_password(void){structtermiosflags,tmp_flags;char*password,*pwd;-intpasslen=64;+constintpasslen=64;-password=malloc(passlen);+password=OPENSSL_secure_malloc(passlen);if(!password){-perror("malloc");+log_err("OPENSSL_secure_malloc(%u) failed\n",passlen);returnNULL;}
From: Stefan Berger <stefanb@linux.ibm.com> Date: 2021-09-05 01:11:01
On 9/4/21 6:50 AM, Vitaly Chikunov wrote:
quoted hunk
After CRYPTO_secure_malloc_init OpenSSL will automatically store private
keys in secure heap. OPENSSL_secure_malloc(3):
If a secure heap is used, then private key BIGNUM values are stored
there. This protects long-term storage of private keys, but will not
necessarily put all intermediate values and computations there.
Additionally, we try to keep user passwords in secure heap too.
This facility is only available since OpenSSL_1_1_0-pre1.
Signed-off-by: Vitaly Chikunov <redacted>
Reviewed-by: Bruno Meneguele <redacted>
Cc: Stefan Berger <stefanb@linux.ibm.com>
---
Change since v3:
- Undo secure heap handling from (file2bin and) calc_evm_hmac since this
is debugging tool only. Add comment about this.
- Since there is only code removals and new comments I keep Reviewed-by
tag.
src/evmctl.c | 97 +++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 85 insertions(+), 12 deletions(-)
@@ -165,6 +166,24 @@ struct tpm_bank_info {staticchar*pcrfile[MAX_PCRFILE];staticunsignednpcrfile;+#if OPENSSL_VERSION_NUMBER <= 0x10100000+#warning Your OpenSSL version is too old to have OPENSSL_secure_malloc, \+fallingbacktouseplainOPENSSL_malloc.+#define OPENSSL_secure_malloc OPENSSL_malloc+#define OPENSSL_secure_free OPENSSL_free+/*+*Secureheapmemoryautomaticallyclearedonfree,but+*OPENSSL_secure_clear_freewillbeusedincaseoffallback+*toplainOPENSSL_malloc.+*/+#define OPENSSL_secure_clear_free OPENSSL_clear_free+#define OPENSSL_clear_free(ptr, num) \+do{\+OPENSSL_cleanse(ptr,num);\+OPENSSL_free(ptr);\+}while(0)+#endif+staticintbin2file(constchar*file,constchar*ext,constunsignedchar*data,intlen){FILE*fp;
@@ -1072,6 +1091,7 @@ static int cmd_setxattr_ima(struct command *cmd)#define MAX_KEY_SIZE 128+/* This function is debugging tool and should not be used for real private data. */staticintcalc_evm_hmac(constchar*file,constchar*keyfile,unsignedchar*hash){constEVP_MD*md;
Mimi applied my patch that takes the password from an environment
variable to the next-testing branch. The code there
(imaevm_params.keypass = getenv("..."))would have to change as well
calling this function here. Even though the man page of getenv says that
'The caller must take care not to modify this string, since that would
change the environment of the process' we should be able to overwrite
the env variable's password value just like here. Maybe for this purpose
rename this function to dup_password() ?
quoted hunk
+ size_t len;
+ char *keypass;
+
+ if (!optarg)
+ return NULL;
+ len = strlen(optarg);
+ keypass = OPENSSL_secure_malloc(len + 1);
+ if (keypass)
+ memcpy(keypass, optarg, len + 1);
+ else
+ log_err("OPENSSL_secure_malloc(%zu) failed\n", len + 1);
+ /*
+ * This memset does not add real security, just increases
+ * the chance of password being obscured in ps output.
+ */
+ memset(optarg, 'X', len);
+ return keypass;
+}
+
+/* Read from TTY into secure heap. */
static char *get_password(void)
{
struct termios flags, tmp_flags;
char *password, *pwd;
- int passlen = 64;
+ const int passlen = 64;
- password = malloc(passlen);
+ password = OPENSSL_secure_malloc(passlen);
if (!password) {
- perror("malloc");
+ log_err("OPENSSL_secure_malloc(%u) failed\n", passlen);
return NULL;
}
@@ -2651,6 +2700,17 @@ int main(int argc, char *argv[]) #endif OPENSSL_INIT_ENGINE_ALL_BUILTIN, NULL); #endif+#if OPENSSL_VERSION_NUMBER > 0x10100000+ /*+ * This facility is available since OpenSSL_1_1_0-pre1.
Shouldn't the comparison then not include 0x10100000?
#if OPENSSL_VERSION_NUMBER >= 0x10100000
quoted hunk
+ * 'Heap size' 8192 is chosen to be big enough, so that any single key
+ * data could fit. 'Heap minsize' 64 is just to be efficient for small
+ * buffers.
+ */
+ if (!CRYPTO_secure_malloc_init(8192, 64))
+ log_err("CRYPTO_secure_malloc_init() failed\n");
+#endif
+
g_argv = argv;
g_argc = argc;
@@ -2682,10 +2742,18 @@ int main(int argc, char *argv[]) imaevm_params.hash_algo = optarg; break; case 'p':+ if (keypass)+ OPENSSL_secure_clear_free(keypass,+ strlen(keypass)); if (optarg)- imaevm_params.keypass = optarg;+ keypass = optarg_password(optarg); else- imaevm_params.keypass = get_password();+ keypass = get_password();+ if (!keypass) {+ log_err("Cannot read password\n");+ goto quit;+ }+ imaevm_params.keypass = keypass; break; case 'f': sigfile = 1;
@@ -2841,7 +2909,9 @@ int main(int argc, char *argv[]) if (err < 0) err = 125; }-+quit:+ if (keypass)+ OPENSSL_secure_clear_free(keypass, strlen(keypass)); if (eng) { ENGINE_finish(eng); ENGINE_free(eng);
Stefan,
On Sat, Sep 04, 2021 at 09:10:50PM -0400, Stefan Berger wrote:
On 9/4/21 6:50 AM, Vitaly Chikunov wrote:
quoted
After CRYPTO_secure_malloc_init OpenSSL will automatically store private
keys in secure heap. OPENSSL_secure_malloc(3):
If a secure heap is used, then private key BIGNUM values are stored
there. This protects long-term storage of private keys, but will not
necessarily put all intermediate values and computations there.
Additionally, we try to keep user passwords in secure heap too.
This facility is only available since OpenSSL_1_1_0-pre1.
Signed-off-by: Vitaly Chikunov <redacted>
Reviewed-by: Bruno Meneguele <redacted>
Cc: Stefan Berger <stefanb@linux.ibm.com>
---
Change since v3:
- Undo secure heap handling from (file2bin and) calc_evm_hmac since this
is debugging tool only. Add comment about this.
- Since there is only code removals and new comments I keep Reviewed-by
tag.
src/evmctl.c | 97 +++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 85 insertions(+), 12 deletions(-)
@@ -2596,15 +2616,41 @@ static struct option opts[] = { };+/*+ * Copy password from optarg into secure heap, so it could be+ * freed in the same way as a result of get_password().+ */+static char *optarg_password(char *optarg)+{
Mimi applied my patch that takes the password from an environment variable
to the next-testing branch. The code there (imaevm_params.keypass =
getenv("..."))would have to change as well calling this function here. Even
though the man page of getenv says that 'The caller must take care not to
modify this string, since that would change the environment of the process'
we should be able to overwrite the env variable's password value just like
here. Maybe for this purpose rename this function to dup_password() ?
`/proc/<pid>/environ' is never world readable (unlike `cmdline'), so we
don't even need to overwrite it there. But, we can.
(Btw, I found the 'EVMCTL_KEY_PASSWORD' patch.)
@@ -2651,6 +2700,17 @@ int main(int argc, char *argv[]) #endif OPENSSL_INIT_ENGINE_ALL_BUILTIN, NULL); #endif+#if OPENSSL_VERSION_NUMBER > 0x10100000+ /*+ * This facility is available since OpenSSL_1_1_0-pre1.
Shouldn't the comparison then not include 0x10100000?
#if OPENSSL_VERSION_NUMBER >= 0x10100000
The number is from `include/openssl/opensslv.h' from the time when
relevant commit is already applied. So, I use `>'. It seems good match
for OpenSSL_1_1_0-pre1 too:
$ git grep OPENSSL_VERSION_NUMBER OpenSSL_1_1_0-pre1:include/openssl/opensslv.h
OpenSSL_1_1_0-pre1:include/openssl/opensslv.h:# define OPENSSL_VERSION_NUMBER 0x10100001L
Thanks,
From: Stefan Berger <stefanb@linux.ibm.com> Date: 2021-09-05 11:52:18
On 9/5/21 4:11 AM, Vitaly Chikunov wrote:
Stefan,
On Sat, Sep 04, 2021 at 09:10:50PM -0400, Stefan Berger wrote:
quoted
On 9/4/21 6:50 AM, Vitaly Chikunov wrote:
quoted
After CRYPTO_secure_malloc_init OpenSSL will automatically store private
keys in secure heap. OPENSSL_secure_malloc(3):
If a secure heap is used, then private key BIGNUM values are stored
there. This protects long-term storage of private keys, but will not
necessarily put all intermediate values and computations there.
Additionally, we try to keep user passwords in secure heap too.
This facility is only available since OpenSSL_1_1_0-pre1.
Signed-off-by: Vitaly Chikunov <redacted>
Reviewed-by: Bruno Meneguele <redacted>
Cc: Stefan Berger <stefanb@linux.ibm.com>
---
Change since v3:
- Undo secure heap handling from (file2bin and) calc_evm_hmac since this
is debugging tool only. Add comment about this.
- Since there is only code removals and new comments I keep Reviewed-by
tag.
src/evmctl.c | 97 +++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 85 insertions(+), 12 deletions(-)
@@ -2596,15 +2616,41 @@ static struct option opts[] = { };+/*+ * Copy password from optarg into secure heap, so it could be+ * freed in the same way as a result of get_password().+ */+static char *optarg_password(char *optarg)+{
Mimi applied my patch that takes the password from an environment variable
to the next-testing branch. The code there (imaevm_params.keypass =
getenv("..."))would have to change as well calling this function here. Even
though the man page of getenv says that 'The caller must take care not to
modify this string, since that would change the environment of the process'
we should be able to overwrite the env variable's password value just like
here. Maybe for this purpose rename this function to dup_password() ?
`/proc/<pid>/environ' is never world readable (unlike `cmdline'), so we
don't even need to overwrite it there. But, we can.
Or you could add an option for whether to overwrite the source...
@@ -2651,6 +2700,17 @@ int main(int argc, char *argv[]) #endif OPENSSL_INIT_ENGINE_ALL_BUILTIN, NULL); #endif+#if OPENSSL_VERSION_NUMBER > 0x10100000+ /*+ * This facility is available since OpenSSL_1_1_0-pre1.
Shouldn't the comparison then not include 0x10100000?
#if OPENSSL_VERSION_NUMBER >= 0x10100000
The number is from `include/openssl/opensslv.h' from the time when
relevant commit is already applied. So, I use `>'. It seems good match
for OpenSSL_1_1_0-pre1 too:
$ git grep OPENSSL_VERSION_NUMBER OpenSSL_1_1_0-pre1:include/openssl/opensslv.h
OpenSSL_1_1_0-pre1:include/openssl/opensslv.h:# define OPENSSL_VERSION_NUMBER 0x10100001L
You are right. I had checkout out this commit here:
commit abd30777cc72029e8a44e4b67201cae8ed3d19c1 (HEAD -> OpenSSL_1_1_0,
tag: OpenSSL_1_1_0)
Author: Matt Caswell [off-list ref]
Date: Thu Aug 25 16:29:18 2016 +0100
Prepare for 1.1.0 release
Reviewed-by: Richard Levitte <levitte@openssl.org
It shows this here:
$ grep -r OPENSSL_VERSION_NUM ./include/
./include/openssl/crypto.h:# define SSLEAY_VERSION_NUMBER
OPENSSL_VERSION_NUMBER
./include/openssl/opensslv.h:# define OPENSSL_VERSION_NUMBER 0x1010000fL
There's an 'f' at the 'end'.
Stefan
On Sat, 2021-09-04 at 13:50 +0300, Vitaly Chikunov wrote:
After CRYPTO_secure_malloc_init OpenSSL will automatically store private
keys in secure heap. OPENSSL_secure_malloc(3):
If a secure heap is used, then private key BIGNUM values are stored
there. This protects long-term storage of private keys, but will not
necessarily put all intermediate values and computations there.
Additionally, we try to keep user passwords in secure heap too.
This facility is only available since OpenSSL_1_1_0-pre1.
Signed-off-by: Vitaly Chikunov <redacted>
Reviewed-by: Bruno Meneguele <redacted>
Cc: Stefan Berger <stefanb@linux.ibm.com>
Thanks, it looks good! Just a few questions inline below.
quoted hunk
---
Change since v3:
- Undo secure heap handling from (file2bin and) calc_evm_hmac since this
is debugging tool only. Add comment about this.
- Since there is only code removals and new comments I keep Reviewed-by
tag.
src/evmctl.c | 97 +++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 85 insertions(+), 12 deletions(-)
@@ -165,6 +166,24 @@ struct tpm_bank_info {staticchar*pcrfile[MAX_PCRFILE];staticunsignednpcrfile;+#if OPENSSL_VERSION_NUMBER <= 0x10100000+#warning Your OpenSSL version is too old to have OPENSSL_secure_malloc, \+fallingbacktouseplainOPENSSL_malloc.+#define OPENSSL_secure_malloc OPENSSL_malloc+#define OPENSSL_secure_free OPENSSL_free+/*+*Secureheapmemoryautomaticallyclearedonfree,but+*OPENSSL_secure_clear_freewillbeusedincaseoffallback+*toplainOPENSSL_malloc.+*/+#define OPENSSL_secure_clear_free OPENSSL_clear_free+#define OPENSSL_clear_free(ptr, num) \+do{\+OPENSSL_cleanse(ptr,num);\+OPENSSL_free(ptr);\+}while(0)+#endif+staticintbin2file(constchar*file,constchar*ext,constunsignedchar*data,intlen){FILE*fp;
@@ -1072,6 +1091,7 @@ static int cmd_setxattr_ima(struct command *cmd)#define MAX_KEY_SIZE 128+/* This function is debugging tool and should not be used for real private data. */staticintcalc_evm_hmac(constchar*file,constchar*keyfile,unsignedchar*hash){constEVP_MD*md;
The reason given for copying the password to secure heap is technically
correct, but could we also include the reason that providing the
password on the command line is unsafe? Perhaps a modified version of
the comment, below, should be included at the beginning of the function
comment.
quoted hunk
+static char *optarg_password(char *optarg)
+{
+ size_t len;
+ char *keypass;
+
+ if (!optarg)
+ return NULL;
+ len = strlen(optarg);
+ keypass = OPENSSL_secure_malloc(len + 1);
+ if (keypass)
+ memcpy(keypass, optarg, len + 1);
+ else
+ log_err("OPENSSL_secure_malloc(%zu) failed\n", len + 1);
+ /*
+ * This memset does not add real security, just increases
+ * the chance of password being obscured in ps output.
+ */
+ memset(optarg, 'X', len);
+ return keypass;
+}
+
+/* Read from TTY into secure heap. */
static char *get_password(void)
{
struct termios flags, tmp_flags;
char *password, *pwd;
- int passlen = 64;
+ const int passlen = 64;
- password = malloc(passlen);
+ password = OPENSSL_secure_malloc(passlen);
if (!password) {
- perror("malloc");
+ log_err("OPENSSL_secure_malloc(%u) failed\n", passlen);
return NULL;
}
@@ -2651,6 +2700,17 @@ int main(int argc, char *argv[]) #endif OPENSSL_INIT_ENGINE_ALL_BUILTIN, NULL); #endif+#if OPENSSL_VERSION_NUMBER > 0x10100000+ /*+ * This facility is available since OpenSSL_1_1_0-pre1.+ * 'Heap size' 8192 is chosen to be big enough, so that any single key+ * data could fit. 'Heap minsize' 64 is just to be efficient for small+ * buffers.+ */
Assuming we aren't guaranteed that the heap size is allocated, should
we check (e.g. OPENSSL_secure_actual_size())?
+ if (!CRYPTO_secure_malloc_init(8192, 64))
+ log_err("CRYPTO_secure_malloc_init() failed\n");
Either change the test to "!= 1" or also log "and 2 if successful but
the heap could not be protected by memory mapping."
quoted hunk
+#endif
+
g_argv = argv;
g_argc = argc;
@@ -2682,10 +2742,18 @@ int main(int argc, char *argv[]) imaevm_params.hash_algo = optarg; break; case 'p':+ if (keypass)+ OPENSSL_secure_clear_free(keypass,+ strlen(keypass));
Is this test needed in case the pasword is provided multiple times?
If so, why not skip subsequent passwords?
Mimi,
On Fri, Sep 10, 2021 at 10:55:04AM -0400, Mimi Zohar wrote:
On Sat, 2021-09-04 at 13:50 +0300, Vitaly Chikunov wrote:
quoted
After CRYPTO_secure_malloc_init OpenSSL will automatically store private
keys in secure heap. OPENSSL_secure_malloc(3):
If a secure heap is used, then private key BIGNUM values are stored
there. This protects long-term storage of private keys, but will not
necessarily put all intermediate values and computations there.
Additionally, we try to keep user passwords in secure heap too.
This facility is only available since OpenSSL_1_1_0-pre1.
Signed-off-by: Vitaly Chikunov <redacted>
Reviewed-by: Bruno Meneguele <redacted>
Cc: Stefan Berger <stefanb@linux.ibm.com>
Thanks, it looks good! Just a few questions inline below.
quoted
---
Change since v3:
- Undo secure heap handling from (file2bin and) calc_evm_hmac since this
is debugging tool only. Add comment about this.
- Since there is only code removals and new comments I keep Reviewed-by
tag.
src/evmctl.c | 97 +++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 85 insertions(+), 12 deletions(-)
@@ -165,6 +166,24 @@ struct tpm_bank_info {staticchar*pcrfile[MAX_PCRFILE];staticunsignednpcrfile;+#if OPENSSL_VERSION_NUMBER <= 0x10100000+#warning Your OpenSSL version is too old to have OPENSSL_secure_malloc, \+fallingbacktouseplainOPENSSL_malloc.+#define OPENSSL_secure_malloc OPENSSL_malloc+#define OPENSSL_secure_free OPENSSL_free+/*+*Secureheapmemoryautomaticallyclearedonfree,but+*OPENSSL_secure_clear_freewillbeusedincaseoffallback+*toplainOPENSSL_malloc.+*/+#define OPENSSL_secure_clear_free OPENSSL_clear_free+#define OPENSSL_clear_free(ptr, num) \+do{\+OPENSSL_cleanse(ptr,num);\+OPENSSL_free(ptr);\+}while(0)+#endif+staticintbin2file(constchar*file,constchar*ext,constunsignedchar*data,intlen){FILE*fp;
@@ -1072,6 +1091,7 @@ static int cmd_setxattr_ima(struct command *cmd)#define MAX_KEY_SIZE 128+/* This function is debugging tool and should not be used for real private data. */staticintcalc_evm_hmac(constchar*file,constchar*keyfile,unsignedchar*hash){constEVP_MD*md;
The reason given for copying the password to secure heap is technically
correct, but could we also include the reason that providing the
password on the command line is unsafe? Perhaps a modified version of
the comment, below, should be included at the beginning of the function
comment.
quoted
+static char *optarg_password(char *optarg)
+{
+ size_t len;
+ char *keypass;
+
+ if (!optarg)
+ return NULL;
+ len = strlen(optarg);
+ keypass = OPENSSL_secure_malloc(len + 1);
+ if (keypass)
+ memcpy(keypass, optarg, len + 1);
+ else
+ log_err("OPENSSL_secure_malloc(%zu) failed\n", len + 1);
+ /*
+ * This memset does not add real security, just increases
+ * the chance of password being obscured in ps output.
+ */
+ memset(optarg, 'X', len);
+ return keypass;
+}
+
+/* Read from TTY into secure heap. */
static char *get_password(void)
{
struct termios flags, tmp_flags;
char *password, *pwd;
- int passlen = 64;
+ const int passlen = 64;
- password = malloc(passlen);
+ password = OPENSSL_secure_malloc(passlen);
if (!password) {
- perror("malloc");
+ log_err("OPENSSL_secure_malloc(%u) failed\n", passlen);
return NULL;
}
@@ -2651,6 +2700,17 @@ int main(int argc, char *argv[]) #endif OPENSSL_INIT_ENGINE_ALL_BUILTIN, NULL); #endif+#if OPENSSL_VERSION_NUMBER > 0x10100000+ /*+ * This facility is available since OpenSSL_1_1_0-pre1.+ * 'Heap size' 8192 is chosen to be big enough, so that any single key+ * data could fit. 'Heap minsize' 64 is just to be efficient for small+ * buffers.+ */
Assuming we aren't guaranteed that the heap size is allocated, should
we check (e.g. OPENSSL_secure_actual_size())?
We guaranteed that secure heap is allocated by return value of
CRYPTO_secure_malloc_init.
OPENSSL_secure_actual_size tell if OPENSSL_secure_malloc is actually
provided bigger memory fragment than we requested (to reduce
fragmentation). Why care about it?
quoted
+ if (!CRYPTO_secure_malloc_init(8192, 64))
+ log_err("CRYPTO_secure_malloc_init() failed\n");
Either change the test to "!= 1" or also log "and 2 if successful but
the heap could not be protected by memory mapping."
Why should we care about implementation details of successful
allocation? If they don't think it's secure heap they should not return
success. And they say about its return value "and 2 if successful but",
so it's successful.
quoted
+#endif
+
g_argv = argv;
g_argc = argc;
@@ -2682,10 +2742,18 @@ int main(int argc, char *argv[]) imaevm_params.hash_algo = optarg; break; case 'p':+ if (keypass)+ OPENSSL_secure_clear_free(keypass,+ strlen(keypass));
Is this test needed in case the pasword is provided multiple times?
It does not care, it just frees memory so there is no leaks. (Perhaps.
it will be cleaned on CRYPTO_secure_malloc_done anyway). I can remove
this check, but why. Then we don't need to free() most of allocations,
because exit will care about all memory. But we free them anyway.
If so, why not skip subsequent passwords?
Old code favored last specified password and I'm just adding secure heap to
it. I don't see that preference to first of last password is better for
UX.
Hi Vitaly,
On Fri, 2021-09-10 at 21:13 +0300, Vitaly Chikunov wrote:
Mimi,
On Fri, Sep 10, 2021 at 10:55:04AM -0400, Mimi Zohar wrote:
quoted
On Sat, 2021-09-04 at 13:50 +0300, Vitaly Chikunov wrote:
quoted
After CRYPTO_secure_malloc_init OpenSSL will automatically store private
keys in secure heap. OPENSSL_secure_malloc(3):
If a secure heap is used, then private key BIGNUM values are stored
there. This protects long-term storage of private keys, but will not
necessarily put all intermediate values and computations there.
Additionally, we try to keep user passwords in secure heap too.
This facility is only available since OpenSSL_1_1_0-pre1.
Signed-off-by: Vitaly Chikunov <redacted>
Reviewed-by: Bruno Meneguele <redacted>
Cc: Stefan Berger <stefanb@linux.ibm.com>
Thanks, it looks good! Just a few questions inline below.
quoted
---
Change since v3:
- Undo secure heap handling from (file2bin and) calc_evm_hmac since this
is debugging tool only. Add comment about this.
- Since there is only code removals and new comments I keep Reviewed-by
tag.
src/evmctl.c | 97 +++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 85 insertions(+), 12 deletions(-)
@@ -165,6 +166,24 @@ struct tpm_bank_info {staticchar*pcrfile[MAX_PCRFILE];staticunsignednpcrfile;+#if OPENSSL_VERSION_NUMBER <= 0x10100000+#warning Your OpenSSL version is too old to have OPENSSL_secure_malloc, \+fallingbacktouseplainOPENSSL_malloc.+#define OPENSSL_secure_malloc OPENSSL_malloc+#define OPENSSL_secure_free OPENSSL_free+/*+*Secureheapmemoryautomaticallyclearedonfree,but+*OPENSSL_secure_clear_freewillbeusedincaseoffallback+*toplainOPENSSL_malloc.+*/+#define OPENSSL_secure_clear_free OPENSSL_clear_free+#define OPENSSL_clear_free(ptr, num) \+do{\+OPENSSL_cleanse(ptr,num);\+OPENSSL_free(ptr);\+}while(0)+#endif+staticintbin2file(constchar*file,constchar*ext,constunsignedchar*data,intlen){FILE*fp;
@@ -1072,6 +1091,7 @@ static int cmd_setxattr_ima(struct command *cmd)#define MAX_KEY_SIZE 128+/* This function is debugging tool and should not be used for real private data. */staticintcalc_evm_hmac(constchar*file,constchar*keyfile,unsignedchar*hash){constEVP_MD*md;
The reason given for copying the password to secure heap is technically
correct, but could we also include the reason that providing the
password on the command line is unsafe? Perhaps a modified version of
the comment, below, should be included at the beginning of the function
comment.
quoted
+static char *optarg_password(char *optarg)
+{
+ size_t len;
+ char *keypass;
+
+ if (!optarg)
+ return NULL;
+ len = strlen(optarg);
+ keypass = OPENSSL_secure_malloc(len + 1);
+ if (keypass)
+ memcpy(keypass, optarg, len + 1);
+ else
+ log_err("OPENSSL_secure_malloc(%zu) failed\n", len + 1);
+ /*
+ * This memset does not add real security, just increases
+ * the chance of password being obscured in ps output.
+ */
+ memset(optarg, 'X', len);
+ return keypass;
+}
+
+/* Read from TTY into secure heap. */
static char *get_password(void)
{
struct termios flags, tmp_flags;
char *password, *pwd;
- int passlen = 64;
+ const int passlen = 64;
- password = malloc(passlen);
+ password = OPENSSL_secure_malloc(passlen);
if (!password) {
- perror("malloc");
+ log_err("OPENSSL_secure_malloc(%u) failed\n", passlen);
return NULL;
}
@@ -2651,6 +2700,17 @@ int main(int argc, char *argv[]) #endif OPENSSL_INIT_ENGINE_ALL_BUILTIN, NULL); #endif+#if OPENSSL_VERSION_NUMBER > 0x10100000+ /*+ * This facility is available since OpenSSL_1_1_0-pre1.+ * 'Heap size' 8192 is chosen to be big enough, so that any single key+ * data could fit. 'Heap minsize' 64 is just to be efficient for small+ * buffers.+ */
Assuming we aren't guaranteed that the heap size is allocated, should
we check (e.g. OPENSSL_secure_actual_size())?
We guaranteed that secure heap is allocated by return value of
CRYPTO_secure_malloc_init.
OPENSSL_secure_actual_size tell if OPENSSL_secure_malloc is actually
provided bigger memory fragment than we requested (to reduce
fragmentation). Why care about it?
We wouldn't care, assuming we're guaranteed the heap size requested was
allocated and not the minimum heap size. Hm, wondering what would be
the purpose of the minimum heap size ...
quoted
quoted
+ if (!CRYPTO_secure_malloc_init(8192, 64))
+ log_err("CRYPTO_secure_malloc_init() failed\n");
Either change the test to "!= 1" or also log "and 2 if successful but
the heap could not be protected by memory mapping."
Why should we care about implementation details of successful
allocation? If they don't think it's secure heap they should not return
success. And they say about its return value "and 2 if successful but",
so it's successful.
If you're correct, then there is no reason ever for returning 2.
Without documentation or digging into OpenSSL, this makes no sense to
me. Perhaps "secure heap" has some kernel dependency, requires HW, or
something else entirely. Not that there is much we could or would do,
but simply ignoring it just seems wrong.
quoted
quoted
+#endif
+
g_argv = argv;
g_argc = argc;
@@ -2682,10 +2742,18 @@ int main(int argc, char *argv[]) imaevm_params.hash_algo = optarg; break; case 'p':+ if (keypass)+ OPENSSL_secure_clear_free(keypass,+ strlen(keypass));
Is this test needed in case the pasword is provided multiple times?
It does not care, it just frees memory so there is no leaks. (Perhaps.
it will be cleaned on CRYPTO_secure_malloc_done anyway). I can remove
this check, but why. Then we don't need to free() most of allocations,
because exit will care about all memory. But we free them anyway.
quoted
If so, why not skip subsequent passwords?
Old code favored last specified password and I'm just adding secure heap to
it. I don't see that preference to first of last password is better for
UX.
Mimi,
On Mon, Sep 13, 2021 at 01:51:58PM -0400, Mimi Zohar wrote:
quoted
quoted
Assuming we aren't guaranteed that the heap size is allocated, should
we check (e.g. OPENSSL_secure_actual_size())?
We guaranteed that secure heap is allocated by return value of
CRYPTO_secure_malloc_init.
OPENSSL_secure_actual_size tell if OPENSSL_secure_malloc is actually
provided bigger memory fragment than we requested (to reduce
fragmentation). Why care about it?
We wouldn't care, assuming we're guaranteed the heap size requested was
allocated and not the minimum heap size. Hm, wondering what would be
the purpose of the minimum heap size ...
Perhaps, just to control heap fragmentation.
quoted
quoted
quoted
+ if (!CRYPTO_secure_malloc_init(8192, 64))
+ log_err("CRYPTO_secure_malloc_init() failed\n");
Either change the test to "!= 1" or also log "and 2 if successful but
the heap could not be protected by memory mapping."
Why should we care about implementation details of successful
allocation? If they don't think it's secure heap they should not return
success. And they say about its return value "and 2 if successful but",
so it's successful.
If you're correct, then there is no reason ever for returning 2.
Without documentation or digging into OpenSSL, this makes no sense to
me. Perhaps "secure heap" has some kernel dependency, requires HW, or
something else entirely. Not that there is much we could or would do,
but simply ignoring it just seems wrong.
I looked at CRYPTO_secure_malloc_init and it seems they return 2 if
mlock/madvise is failed. I think it's major enough to report it, so I
will add it.
Thanks,
Hi Vitaly, Stefan,
On Fri, 2021-09-10 at 10:55 -0400, Mimi Zohar wrote:
What was the conclusion in terms of reading the password stored in the
environment variable?
If this is an issue, perhaps call the equivalent of optarg_password()
to store the environment variable in secure heap memory.
Something like:
imaevm_params.keypass =
optarg_password(getenv("EVMCTL_KEY_PASSWORD"));
optarg_password() would then become a wrapper around the new function.
thanks,
Mimi