Blob Blame History Raw
From cf7ea69fe12f61a31c052a08352109646b16650f Mon Sep 17 00:00:00 2001
From: Stanislav Levin <slev@altlinux.org>
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 "|<absolute-command-path>", the
      implementation SHOULD read the PIN from the output of an
      application specified with absolute path "<absolute-command-
      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 <ortigali.bazarov@gmail.com>
Signed-off-by: Stanislav Levin <slev@altlinux.org>
(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 <stdio.h>
 #include <string.h>
 
+#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