[v2] signature: allow codeSigning as key usage

Message ID 20181009072622.25164-1-Denis.Osterland@diehl.com
State New
Headers show
Series
  • [v2] signature: allow codeSigning as key usage
Related show

Commit Message

Denis OSTERLAND Oct. 9, 2018, 7:33 a.m.
OpenSSL CMS checks only for emailProtection key usage,
but codeSigning makes more sense here.
This patch adds command line parameter and configuration variable
to set expected certificate purpose.

Signed-off-by: Denis Osterland <Denis.Osterland@diehl.com>
---
v1 -> v2: set expected purpose before call to verify,
          add configuration options for the expected purpose

 core/swupdate.c            | 26 ++++++++++++++++++++++++++
 corelib/verify_signature.c | 25 +++++++++++++++++++++++++
 include/sslapi.h           |  2 ++
 include/swupdate.h         |  1 +
 4 files changed, 54 insertions(+)

Patch

diff --git a/core/swupdate.c b/core/swupdate.c
index 161b03f..f3a9b1f 100644
--- a/core/swupdate.c
+++ b/core/swupdate.c
@@ -81,6 +81,7 @@  static struct option long_options[] = {
 	{"no-downgrading", required_argument, NULL, 'N'},
 #ifdef CONFIG_SIGNED_IMAGES
 	{"key", required_argument, NULL, 'k'},
+	{"cert-purpose", required_argument, NULL, '1'},
 #endif
 #ifdef CONFIG_ENCRYPTED_IMAGES
 	{"key-aes", required_argument, NULL, 'K'},
@@ -126,6 +127,8 @@  static void usage(char *programname)
 		" -L, --syslog                   : enable syslog logger\n"
 #ifdef CONFIG_SIGNED_IMAGES
 		" -k, --key <public key file>    : file with public key to verify images\n"
+		"     --cert-purpose <purpose>   : set expected certificate purpose\n"
+		"                                  [emailProtection|codeSigning] (default: emailProtection)\n"
 #endif
 #ifdef CONFIG_ENCRYPTED_IMAGES
 		" -K, --key-aes <key file>       : the file contains the symmetric key to be used\n"
@@ -446,6 +449,7 @@  static void swupdate_init(struct swupdate_cfg *sw)
 	LIST_INIT(&sw->bootscripts);
 	LIST_INIT(&sw->bootloader);
 	LIST_INIT(&sw->extprocs);
+	sw->globals.cert_purpose = X509_PURPOSE_SMIME_SIGN;
 
 
 	/* Create directories for scripts */
@@ -462,8 +466,24 @@  static void swupdate_init(struct swupdate_cfg *sw)
 #endif
 }
 
+static int parse_cert_purpose(const char *text)
+{
+	static const char CODE_SIGN[] = "codeSigning";
+	static const char EMAIL_PROT[] = "emailProtection";
+
+	if (strncmp(CODE_SIGN, text, sizeof(CODE_SIGN)) == 0)
+		return X509_PURPOSE_CODE_SIGN;
+
+	if (strncmp(EMAIL_PROT, text, sizeof(EMAIL_PROT)) == 0)
+		return X509_PURPOSE_SMIME_SIGN;
+
+	ERROR("unknown certificate purpose '%s'\n", text);
+	exit(EXIT_FAILURE);
+}
+
 static int read_globals_settings(void *elem, void *data)
 {
+	char tmp[SWUPDATE_GENERAL_STRING_SIZE];
 	struct swupdate_cfg *sw = (struct swupdate_cfg *)data;
 
 	GET_FIELD_STRING(LIBCFG_PARSER, elem,
@@ -481,6 +501,9 @@  static int read_globals_settings(void *elem, void *data)
 				"no-downgrading", sw->globals.current_version);
 	if (strlen(sw->globals.current_version))
 		sw->globals.no_downgrading = 1;
+	GET_FIELD_STRING(LIBCFG_PARSER, elem,
+				"cert-purpose", tmp);
+	sw->globals.cert_purpose = parse_cert_purpose(tmp);
 
 	return 0;
 }
@@ -694,6 +717,9 @@  int main(int argc, char **argv)
 				optarg,
 			       	sizeof(swcfg.globals.publickeyfname));
 			break;
+		case '1':
+			swcfg.globals.cert_purpose = parse_cert_purpose(optarg);
+			break;
 #ifdef CONFIG_ENCRYPTED_IMAGES
 		case 'K':
 			strncpy(swcfg.globals.aeskeyfname,
diff --git a/corelib/verify_signature.c b/corelib/verify_signature.c
index 6ddfa42..f37b678 100644
--- a/corelib/verify_signature.c
+++ b/corelib/verify_signature.c
@@ -195,6 +195,13 @@  out:
 }
 
 #elif defined(CONFIG_SIGALG_CMS)
+static int check_purpose_code_sign(const X509_PURPOSE *xp, const X509 *x,
+                                   int ca)
+{
+	(void)xp;
+	(void)ca;
+	return (x->ex_flags & EXFLAG_XKUSAGE) && (x->ex_xkusage & XKU_CODE_SIGN);
+}
 static int cms_verify_callback(int ok, X509_STORE_CTX *ctx) {
 	int cert_error = X509_STORE_CTX_get_error(ctx);
 
@@ -439,6 +446,24 @@  int swupdate_dgst_init(struct swupdate_cfg *sw, const char *keyfile)
 		ret = -EINVAL;
 		goto dgst_init_error;
 	}
+
+	{
+		static char code_sign_name[] = "Code signing";
+		static char code_sign_sname[] = "codesign";
+		if (!X509_PURPOSE_add(X509_PURPOSE_CODE_SIGN, X509_TRUST_EMAIL,
+				0, check_purpose_code_sign, code_sign_name,
+				code_sign_sname, NULL)) {
+			ERROR("failed to add code sign purpose");
+			ret = -EINVAL;
+			goto dgst_init_error;
+		}
+	}
+
+	if (!X509_STORE_set_purpose(dgst->certs, sw->globals.cert_purpose)) {
+		ERROR("failed to set purpose");
+		ret = -EINVAL;
+		goto dgst_init_error;
+	}
 #else
 	TRACE("public key / cert %s ignored, you need to set SIGALG", keyfile);
 #endif
diff --git a/include/sslapi.h b/include/sslapi.h
index 1d24dfb..3edc621 100644
--- a/include/sslapi.h
+++ b/include/sslapi.h
@@ -36,6 +36,8 @@ 
 
 #include <openssl/opensslv.h>
 
+#define X509_PURPOSE_CODE_SIGN (X509_PURPOSE_MAX + 1)
+
 struct swupdate_digest {
 	EVP_PKEY *pkey;		/* this is used for RSA key */
 	X509_STORE *certs;	/* this is used if CMS is set */
diff --git a/include/swupdate.h b/include/swupdate.h
index 741d24c..cd83d6f 100644
--- a/include/swupdate.h
+++ b/include/swupdate.h
@@ -112,6 +112,7 @@  struct swupdate_global_cfg {
 	char aeskeyfname[SWUPDATE_GENERAL_STRING_SIZE];
 	char postupdatecmd[SWUPDATE_GENERAL_STRING_SIZE];
 	char current_version[SWUPDATE_GENERAL_STRING_SIZE];
+	int cert_purpose;
 };
 
 struct swupdate_cfg {