Skip to content

Commit

Permalink
PEM: support passwords via --passin
Browse files Browse the repository at this point in the history
The OSSL PEM reading routines allow various callbacks and password options to
allow for decrypting encrypted PEM files. Initially, this was configure in a
way to make OSSL prompt for the password, which was precluding input from
other sources like stdin.

Allow additional sources via --passin option in a way similair to OSSL's
passin argument.

Signed-off-by: William Roberts <william.c.roberts@intel.com>
  • Loading branch information
William Roberts committed Oct 30, 2018
1 parent 0a712a2 commit b008a17
Show file tree
Hide file tree
Showing 9 changed files with 302 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,7 @@
## Changelog
### next
* tpm2_loadexternal: support OSSL style -passin argument as --passin for PEM file passwords.
* tpm2_import: support OSSL style -passin argument as --passin for PEM file passwords.
* tpm2_readpublic: supports ECC pem and der file generation.
* tpm2_activatecredential: Option `--endorse-passwd` changes to `--auth-endorse`.
* tpm2_loadexternal: name output to file and stdout. Changes YAML stdout output.
Expand Down
208 changes: 200 additions & 8 deletions lib/tpm2_openssl.c
Expand Up @@ -26,6 +26,7 @@
//**********************************************************************

#include <errno.h>
#include <stdint.h>
#include <string.h>

#include <openssl/aes.h>
Expand Down Expand Up @@ -186,6 +187,178 @@ digester tpm2_openssl_halg_to_digester(TPMI_ALG_HASH halg) {
return NULL;
}

/*
* Per man openssl(1), handle the following --passin formats:
* pass:password
* the actual password is password. Since the password is visible to utilities (like 'ps' under Unix) this form should only be used where security is not
* important.
*
* env:var obtain the password from the environment variable var. Since the environment of other processes is visible on certain platforms (e.g. ps under certain
* Unix OSes) this option should be used with caution.
*
* file:pathname
* the first line of pathname is the password. If the same pathname argument is supplied to -passin and -passout arguments then the first line will be used
* for the input password and the next line for the output password. pathname need not refer to a regular file: it could for example refer to a device or
* named pipe.
*
* fd:number read the password from the file descriptor number. This can be used to send the data via a pipe for example.
*
* stdin read the password from standard input.
*
*/

typedef bool (*pfn_ossl_pw_handler)(const char *passin, char **pass);

static bool do_pass(const char *passin, char **pass) {

char *tmp = strdup(passin);
if (!tmp) {
LOG_ERR("oom");
return false;
}

*pass = tmp;
return true;
}

static bool do_env(const char *envvar, char **pass) {

char *tmp = getenv(envvar);
if (!tmp) {
LOG_ERR("Environment variable \"%s\" not found", envvar);
return false;
}

tmp = strdup(tmp);
if (!tmp) {
LOG_ERR("oom");
return false;
}

*pass = tmp;
return true;
}

static bool do_open_file(FILE *f, const char *path, char **pass) {

bool rc = false;

unsigned long file_size = 0;
bool result = files_get_file_size(f, &file_size, path);
if (!result) {
goto out;
}

if (file_size + 1 <= file_size) {
LOG_ERR("overflow: file_size too large");
goto out;
}

char *tmp = calloc(sizeof(char), file_size + 1);
if (!tmp) {
LOG_ERR("oom");
goto out;
}

result = files_read_bytes(f, (UINT8 *)tmp, file_size);
if (!result) {
goto out;
}

*pass = tmp;

rc = true;

out:
fclose(f);

return rc;
}

static bool do_file(const char *path, char **pass) {

FILE *f = fopen(path, "rb");
if (!f) {
LOG_ERR("could not open file \"%s\" error: %s",
path, strerror(errno));
return false;
}

return do_open_file(f, path, pass);
}

static bool do_fd(const char *passin, char **pass) {

char *end_ptr = NULL;
int fd = strtoul(passin, &end_ptr, 0);
if (passin[0] != '\0' && end_ptr[0] != '\0') {
LOG_ERR("Invalid fd, got: \"%s\"", passin);
return false;
}

FILE *f = fdopen(fd, "rb");
if (!f) {
LOG_ERR("could not open fd \"%d\" error: %s",
fd, strerror(errno));
return false;
}

return do_open_file(f, "fd", pass);
}

static bool do_stdin(const char *passin, char **pass) {

UNUSED(passin);

void *buf = calloc(sizeof(BYTE), UINT16_MAX + 1);
if (!buf) {
LOG_ERR("oom");
return false;
}

UINT16 size = UINT16_MAX;

bool result = files_load_bytes_from_file_or_stdin(NULL, &size, buf);
if (!result) {
free(buf);
return false;
}

*pass = buf;
return true;
}

static bool handle_ossl_pass(const char *passin, char **pass) {

pfn_ossl_pw_handler pfn = NULL;

if (!passin) {
*pass = NULL;
return true;
}

if (!strncmp("pass:", passin, 5)) {
passin += 5;
pfn = do_pass;
} else if (!strncmp("env:", passin, 4)) {
pfn = do_env;
passin += 4;
} else if (!strncmp("file:", passin, 5)) {
pfn = do_file;
passin += 5;
} else if (!strncmp("fd:", passin, 3)) {
pfn = do_fd;
passin += 3;
} else if (!strcmp("stdin", passin)) {
pfn = do_stdin;
} else {
LOG_ERR("Unknown OSSL style password argument, got: \"%s\"", passin);
return false;
}

return pfn(passin, pass);
}

static bool load_public_RSA_from_key(RSA *k, TPM2B_PUBLIC *pub) {

TPMT_PUBLIC *pt = &pub->publicArea;
Expand Down Expand Up @@ -585,20 +758,27 @@ bool tpm2_openssl_load_public(const char *path, TPMI_ALG_PUBLIC alg, TPM2B_PUBLI
return true;
}

static tpm2_openssl_load_rc load_private_ECC_from_pem(FILE *f, const char *path, TPM2B_PUBLIC *pub, TPM2B_SENSITIVE *priv) {
static tpm2_openssl_load_rc load_private_ECC_from_pem(FILE *f, const char *path, const char *passin, TPM2B_PUBLIC *pub, TPM2B_SENSITIVE *priv) {

tpm2_openssl_load_rc rc = lprc_error;

char *pass = NULL;
bool result = handle_ossl_pass(passin, &pass);
if (!result) {
return lprc_error;
}

EC_KEY *k = PEM_read_ECPrivateKey(f, NULL,
NULL, NULL);
NULL, (void *)pass);
free(pass);
fclose(f);
if (!k) {
ERR_print_errors_fp (stderr);
LOG_ERR("Reading PEM file \"%s\" failed", path);
return lprc_error;
}

bool result = load_private_ECC_from_key(k, priv);
result = load_private_ECC_from_key(k, priv);
if (!result) {
rc = lprc_error;
goto out;
Expand All @@ -619,14 +799,22 @@ static tpm2_openssl_load_rc load_private_ECC_from_pem(FILE *f, const char *path,
return rc;
}

static tpm2_openssl_load_rc load_private_RSA_from_pem(FILE *f, const char *path, TPM2B_PUBLIC *pub, TPM2B_SENSITIVE *priv) {
static tpm2_openssl_load_rc load_private_RSA_from_pem(FILE *f, const char *path, const char *passin,
TPM2B_PUBLIC *pub, TPM2B_SENSITIVE *priv) {

RSA *k = NULL;

tpm2_openssl_load_rc rc = lprc_error;

char *pass = NULL;
bool result = handle_ossl_pass(passin, &pass);
if (!result) {
return lprc_error;
}

k = PEM_read_RSAPrivateKey(f, NULL,
NULL, NULL);
NULL, (void *)pass);
free(pass);
fclose(f);
if (!k) {
ERR_print_errors_fp (stderr);
Expand Down Expand Up @@ -700,7 +888,7 @@ static tpm2_openssl_load_rc load_private_AES_from_file(FILE *f, const char *path
* @returns
* A private object loading status
*/
tpm2_openssl_load_rc tpm2_openssl_load_private(const char *path, TPMI_ALG_PUBLIC alg, TPM2B_PUBLIC *pub, TPM2B_SENSITIVE *priv) {
tpm2_openssl_load_rc tpm2_openssl_load_private(const char *path, const char *pass, TPMI_ALG_PUBLIC alg, TPM2B_PUBLIC *pub, TPM2B_SENSITIVE *priv) {

FILE *f = fopen(path, "r");
if (!f) {
Expand All @@ -718,13 +906,17 @@ tpm2_openssl_load_rc tpm2_openssl_load_private(const char *path, TPMI_ALG_PUBLIC

switch (alg) {
case TPM2_ALG_RSA:
rc = load_private_RSA_from_pem(f, path, pub, priv);
rc = load_private_RSA_from_pem(f, path, pass, pub, priv);
break;
case TPM2_ALG_AES:
if (pass) {
LOG_ERR("No password can be used for protecting AES key");
return lprc_error;
}
rc = load_private_AES_from_file(f, path, pub, priv);
break;
case TPM2_ALG_ECC:
rc =load_private_ECC_from_pem(f, path, pub, priv);
rc =load_private_ECC_from_pem(f, path, pass, pub, priv);
break;
default:
LOG_ERR("Cannot handle algorithm, got: %s", tpm2_alg_util_algtostr(alg,
Expand Down
8 changes: 5 additions & 3 deletions lib/tpm2_openssl.h
Expand Up @@ -141,12 +141,14 @@ static inline bool tpm2_openssl_did_load_public(tpm2_openssl_load_rc load_status
* For symmetric keys, the file type is raw. For asymmetric keys, the
* file type is a PEM file.
*
* This ONLY supports AES and RSA.
* This ONLY supports AES, ECC and RSA.
*
* It populates the sensitive seed with a random value for symmetric keys.
*
* @param path
* The path to load from.
* @param path
* The passphrase for the input file.
* @param alg
* algorithm type to import.
* @param pub
Expand All @@ -157,8 +159,8 @@ static inline bool tpm2_openssl_did_load_public(tpm2_openssl_load_rc load_status
* @returns
* A private object loading status
*/
tpm2_openssl_load_rc tpm2_openssl_load_private(const char *path, TPMI_ALG_PUBLIC alg,
TPM2B_PUBLIC *pub, TPM2B_SENSITIVE *priv);
tpm2_openssl_load_rc tpm2_openssl_load_private(const char *path, const char *pass,
TPMI_ALG_PUBLIC alg, TPM2B_PUBLIC *pub, TPM2B_SENSITIVE *priv);

/**
* Loads a public portion of a key from a file. Files can be the raw key, in the case
Expand Down
5 changes: 5 additions & 0 deletions man/tpm2_import.1.md
Expand Up @@ -56,6 +56,11 @@ These options control the key importation process:
* **-A**, **--object-attributes**=_ATTRIBUTES_:
The object attributes, optional.

* **--passin**=_OSSL\_PEM\_FILE\_PASSWORD_
An optional password for an Open SSL (OSSL) provided input file. It mirrors the -passin option of
OSSL and is known to support the pass, file, env, fd and plain password formats of openssl.
(see *man(1) openssl*) for more.

[common options](common/options.md)

[common tcti options](common/tcti.md)
Expand Down
5 changes: 5 additions & 0 deletions man/tpm2_loadexternal.1.md
Expand Up @@ -99,6 +99,11 @@ name: 0x000b44e59fa5658ab443834a069a488ecc1f6d7deb47c40c6ec49871ef57d7036b43
An optional file to save the object name, which is in a binary hash format. The size of the hash is
based on name algorithm or the **-g** option.

* **--passin**=_OSSL\_PEM\_FILE\_PASSWORD_
An optional password for an Open SSL (OSSL) provided input file. It mirrors the -passin option of
OSSL and is known to support the pass, file, env, fd and plain password formats of openssl.
(see *man(1) openssl*) for more.

# Notes

* If the hierarchy is *null* or the name hashing algorithm is *null*, tickets produced using the object
Expand Down

0 comments on commit b008a17

Please sign in to comment.