From cf7ea69fe12f61a31c052a08352109646b16650f Mon Sep 17 00:00:00 2001 From: Stanislav Levin Date: Wed, 11 Sep 2019 15:40:34 +0300 Subject: [PATCH] Add support for pin-source within PKCS11 URI According to https://tools.ietf.org/html/rfc7512#page-9: """ 2.4. PKCS #11 URI Scheme Query Attribute Semantics An application can always ask for a PIN by any means it decides to. What is more, in order not to limit PKCS #11 URI portability, the "pin-source" attribute value format and interpretation is left to be implementation specific. However, the following rules SHOULD be followed in descending order for the value of the "pin-source" attribute: o If the value represents a URI, it SHOULD be treated as an object containing the PIN. Such a URI may be "file:", "https:", another PKCS #11 URI, or something else. o If the value contains "|", the implementation SHOULD read the PIN from the output of an application specified with absolute path "". Note that character "|" representing a pipe does not have to be percent-encoded in the query component of a PKCS #11 URI. o Interpret the value as needed in an implementation-dependent way. """ This patch is based on: https://github.com/OpenSC/libp11/pull/236, but implements only the first clause of RFC, since the second one is considered as dangerous. For example, such functionality is required by FreeIPA (Bind + OpenDNSSEC). Fixes: https://github.com/OpenSC/libp11/issues/273 Co-authored-by: Ortigali Bazarov Signed-off-by: Stanislav Levin (cherry picked from commit 10295b7eb531aef1a9f7e990d5f2527c420b3b72) --- src/eng_parse.c | 55 ++++++++++++++++++++++++++++++++++- tests/rsa-evp-sign.softhsm | 59 ++++++++++++++++++++++++-------------- 2 files changed, 91 insertions(+), 23 deletions(-) diff --git a/src/eng_parse.c b/src/eng_parse.c index f9d69e4..0c164c9 100644 --- a/src/eng_parse.c +++ b/src/eng_parse.c @@ -30,6 +30,10 @@ #include #include +#if defined(_WIN32) || defined(_WIN64) +#define strncasecmp _strnicmp +#endif + static int hex_to_bin(ENGINE_CTX *ctx, const char *in, unsigned char *out, size_t *outlen) { @@ -263,6 +267,51 @@ static int parse_uri_attr(ENGINE_CTX *ctx, return ret; } +static int read_from_file(ENGINE_CTX *ctx, + const char *path, char *field, size_t *field_len) +{ + BIO *fp; + + fp = BIO_new_file(path, "r"); + if (fp == NULL) { + ctx_log(ctx, 0, "Could not open file %s\n", path); + return 0; + } + if (BIO_gets(fp, field, *field_len) > 0) { + *field_len = strlen(field); + } else { + *field_len = 0; + } + + BIO_free(fp); + return 1; +} + +static int parse_pin_source(ENGINE_CTX *ctx, + const char *attr, int attrlen, unsigned char *field, + size_t *field_len) +{ + unsigned char *val; + int ret = 1; + + if (!parse_uri_attr(ctx, attr, attrlen, &val, NULL)) { + return 0; + } + + if (!strncasecmp((const char *)val, "file:", 5)) { + ret = read_from_file(ctx, (const char *)(val + 5), (char *)field, field_len); + } else if (*val == '|') { + ret = 0; + ctx_log(ctx, 0, "Unsupported pin-source syntax\n"); + /* 'pin-source=/foo/bar' is commonly used */ + } else { + ret = read_from_file(ctx, (const char *)val, (char *)field, field_len); + } + OPENSSL_free(val); + + return ret; +} + int parse_pkcs11_uri(ENGINE_CTX *ctx, const char *uri, PKCS11_TOKEN **p_tok, unsigned char *id, size_t *id_len, char *pin, size_t *pin_len, @@ -309,7 +358,11 @@ int parse_pkcs11_uri(ENGINE_CTX *ctx, id_set = 1; } else if (!strncmp(p, "pin-value=", 10)) { p += 10; - rv = parse_uri_attr(ctx, p, end - p, (void *)&pin, pin_len); + rv = pin_set ? 0 : parse_uri_attr(ctx, p, end - p, (void *)&pin, pin_len); + pin_set = 1; + } else if (!strncmp(p, "pin-source=", 11)) { + p += 11; + rv = pin_set ? 0 : parse_pin_source(ctx, p, end - p, (unsigned char *)pin, pin_len); pin_set = 1; } else if (!strncmp(p, "type=", 5) || !strncmp(p, "object-type=", 12)) { p = strchr(p, '=') + 1; diff --git a/tests/rsa-evp-sign.softhsm b/tests/rsa-evp-sign.softhsm index 7ef993d..bcc1cad 100755 --- a/tests/rsa-evp-sign.softhsm +++ b/tests/rsa-evp-sign.softhsm @@ -26,33 +26,48 @@ common_init sed -e "s|@MODULE_PATH@|${MODULE}|g" -e "s|@ENGINE_PATH@|../src/.libs/pkcs11.so|g" <"${srcdir}/engines.cnf.in" >"${outdir}/engines.cnf" +echo -n $PIN > $outdir/pin.txt + export OPENSSL_ENGINES="../src/.libs/" -PRIVATE_KEY="pkcs11:token=libp11-test;id=%01%02%03%04;object=server-key;type=private;pin-value=1234" -PUBLIC_KEY="pkcs11:token=libp11-test;id=%01%02%03%04;object=server-key;type=public;pin-value=1234" -./evp-sign ctrl false "${outdir}/engines.cnf" ${PRIVATE_KEY} ${PUBLIC_KEY} ${MODULE} -if test $? != 0;then - echo "Basic PKCS #11 test, using ctrl failed" - exit 1; -fi +KEY_ID="pkcs11:token=libp11-test;id=%01%02%03%04;object=server-key" -./evp-sign default false "${outdir}/engines.cnf" ${PRIVATE_KEY} ${PUBLIC_KEY} ${MODULE} -if test $? != 0;then - echo "Basic PKCS #11 test, using default failed" - exit 1; -fi +for PIN_ATTR in \ + "pin-value=1234" \ + "pin-source=$outdir/pin.txt" \ + "pin-source=file:$outdir/pin.txt" +do -./evp-sign ctrl 1234 "${outdir}/engines.cnf" ${PRIVATE_KEY} ${PUBLIC_KEY} ${MODULE} -if test $? != 0;then - echo "Basic PKCS #11 test without pin-value, using ctrl failed" - exit 1; -fi + PRIVATE_KEY="$KEY_ID;type=private;$PIN_ATTR" + PUBLIC_KEY="$KEY_ID;type=public;$PIN_ATTR" -./evp-sign default 1234 "${outdir}/engines.cnf" ${PRIVATE_KEY} ${PUBLIC_KEY} ${MODULE} -if test $? != 0;then - echo "Basic PKCS #11 test without pin-value, using default failed" - exit 1; -fi + echo $PRIVATE_KEY + + ./evp-sign ctrl false "${outdir}/engines.cnf" ${PRIVATE_KEY} ${PUBLIC_KEY} ${MODULE} + if test $? != 0;then + echo "Basic PKCS #11 test, using ctrl failed" + exit 1; + fi + + ./evp-sign default false "${outdir}/engines.cnf" ${PRIVATE_KEY} ${PUBLIC_KEY} ${MODULE} + if test $? != 0;then + echo "Basic PKCS #11 test, using default failed" + exit 1; + fi + + ./evp-sign ctrl 1234 "${outdir}/engines.cnf" ${PRIVATE_KEY} ${PUBLIC_KEY} ${MODULE} + if test $? != 0;then + echo "Basic PKCS #11 test without pin-value, using ctrl failed" + exit 1; + fi + + ./evp-sign default 1234 "${outdir}/engines.cnf" ${PRIVATE_KEY} ${PUBLIC_KEY} ${MODULE} + if test $? != 0;then + echo "Basic PKCS #11 test without pin-value, using default failed" + exit 1; + fi + +done ./evp-sign ctrl 1234 "${outdir}/engines.cnf" "label_server-key" "label_server-key" ${MODULE} if test $? != 0;then -- 2.21.0