lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Sat, 30 Jan 2016 10:18:17 +0100
From:	Juerg Haefliger <juerg.haefliger@....com>
To:	linux-kernel@...r.kernel.org, keyrings@...r.kernel.org
Cc:	dhowells@...hat.com, dwmw2@...radead.org
Subject: [PATCH] scripts/sign-file.c: Add support for signing with a raw signature

This commit adds support for signing a kernel module with a raw
detached PKCS#7 signature/message.

The signature is not converted and is simply appended to the module so
it needs to be in the right format. Using openssl, a valid signature can
be generated like this:
  $ openssl smime -sign -nocerts -noattr -binary -in <module> -inkey \
    <key> -signer <x509> -outform der -out <raw sig>

The resulting raw signature from the above command is (more or less)
identical to the raw signature that sign-file itself can produce like
this:
  $ scripts/sign-file -d <hash algo> <key> <x509> <module>

Signed-off-by: Juerg Haefliger <juerg.haefliger@....com>
---
 scripts/sign-file.c | 213 +++++++++++++++++++++++++++++++++-------------------
 1 file changed, 135 insertions(+), 78 deletions(-)

diff --git a/scripts/sign-file.c b/scripts/sign-file.c
index 250a7a6..d23fe70 100755
--- a/scripts/sign-file.c
+++ b/scripts/sign-file.c
@@ -2,9 +2,11 @@
  *
  * Copyright © 2014-2015 Red Hat, Inc. All Rights Reserved.
  * Copyright © 2015      Intel Corporation.
+ * Copyright © 2016      Hewlett Packard Enterprise Development Company, L.P.
  *
  * Authors: David Howells <dhowells@...hat.com>
  *          David Woodhouse <dwmw2@...radead.org>
+ *          Juerg Haefliger <juerg.haefliger@....com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -67,6 +69,8 @@ void format(void)
 {
 	fprintf(stderr,
 		"Usage: scripts/sign-file [-dp] <hash algo> <key> <x509> <module> [<dest>]\n");
+	fprintf(stderr,
+		"       scripts/sign-file -s <raw sig> <hash algo> <x509> <module> [<dest>]\n");
 	exit(2);
 }
 
@@ -126,26 +130,84 @@ static int pem_pw_cb(char *buf, int len, int w, void *v)
 	return pwlen;
 }
 
+static EVP_PKEY *read_private_key(char *private_key_name)
+{
+	EVP_PKEY *private_key;
+
+	if (!strncmp(private_key_name, "pkcs11:", 7)) {
+		ENGINE *e;
+
+		ENGINE_load_builtin_engines();
+		drain_openssl_errors();
+		e = ENGINE_by_id("pkcs11");
+		ERR(!e, "Load PKCS#11 ENGINE");
+		if (ENGINE_init(e))
+			drain_openssl_errors();
+		else
+			ERR(1, "ENGINE_init");
+		if (key_pass)
+			ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0),
+			    "Set PKCS#11 PIN");
+		private_key = ENGINE_load_private_key(e, private_key_name,
+						      NULL, NULL);
+		ERR(!private_key, "%s", private_key_name);
+	} else {
+		BIO *b;
+
+		b = BIO_new_file(private_key_name, "rb");
+		ERR(!b, "%s", private_key_name);
+		private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb,
+						      NULL);
+		ERR(!private_key, "%s", private_key_name);
+		BIO_free(b);
+	}
+
+	return private_key;
+}
+
+static X509 *read_x509(char *x509_name)
+{
+	X509 *x509;
+	BIO *b;
+
+	b = BIO_new_file(x509_name, "rb");
+	ERR(!b, "%s", x509_name);
+	x509 = d2i_X509_bio(b, NULL); /* Binary encoded X.509 */
+	if (!x509) {
+		ERR(BIO_reset(b) != 1, "%s", x509_name);
+		x509 = PEM_read_bio_X509(b, NULL, NULL,
+					 NULL); /* PEM encoded X.509 */
+		if (x509)
+			drain_openssl_errors();
+	}
+	BIO_free(b);
+	ERR(!x509, "%s", x509_name);
+
+	return x509;
+}
+
 int main(int argc, char **argv)
 {
 	struct module_signature sig_info = { .id_type = PKEY_ID_PKCS7 };
 	char *hash_algo = NULL;
-	char *private_key_name, *x509_name, *module_name, *dest_name;
+	char *private_key_name = NULL, *raw_sig_name = NULL;
+	char *x509_name, *module_name, *dest_name;
 	bool save_sig = false, replace_orig;
 	bool sign_only = false;
+	bool raw_sig = false;
 	unsigned char buf[4096];
 	unsigned long module_size, sig_size;
 	unsigned int use_signed_attrs;
 	const EVP_MD *digest_algo;
 	EVP_PKEY *private_key;
 #ifndef USE_PKCS7
-	CMS_ContentInfo *cms;
+	CMS_ContentInfo *cms = NULL;
 	unsigned int use_keyid = 0;
 #else
-	PKCS7 *pkcs7;
+	PKCS7 *pkcs7 = NULL;
 #endif
 	X509 *x509;
-	BIO *b, *bd = NULL, *bm;
+	BIO *bd, *bm;
 	int opt, n;
 	OpenSSL_add_all_algorithms();
 	ERR_load_crypto_strings();
@@ -160,8 +222,9 @@ int main(int argc, char **argv)
 #endif
 
 	do {
-		opt = getopt(argc, argv, "dpk");
+		opt = getopt(argc, argv, "sdpk");
 		switch (opt) {
+		case 's': raw_sig = true; break;
 		case 'p': save_sig = true; break;
 		case 'd': sign_only = true; save_sig = true; break;
 #ifndef USE_PKCS7
@@ -177,8 +240,13 @@ int main(int argc, char **argv)
 	if (argc < 4 || argc > 5)
 		format();
 
-	hash_algo = argv[0];
-	private_key_name = argv[1];
+	if (raw_sig) {
+		raw_sig_name = argv[0];
+		hash_algo = argv[1];
+	} else {
+		hash_algo = argv[0];
+		private_key_name = argv[1];
+	}
 	x509_name = argv[2];
 	module_name = argv[3];
 	if (argc == 5) {
@@ -198,84 +266,50 @@ int main(int argc, char **argv)
 	}
 #endif
 
-	/* Read the private key and the X.509 cert the PKCS#7 message
-	 * will point to.
-	 */
-	if (!strncmp(private_key_name, "pkcs11:", 7)) {
-		ENGINE *e;
-
-		ENGINE_load_builtin_engines();
-		drain_openssl_errors();
-		e = ENGINE_by_id("pkcs11");
-		ERR(!e, "Load PKCS#11 ENGINE");
-		if (ENGINE_init(e))
-			drain_openssl_errors();
-		else
-			ERR(1, "ENGINE_init");
-		if (key_pass)
-			ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN");
-		private_key = ENGINE_load_private_key(e, private_key_name, NULL,
-						      NULL);
-		ERR(!private_key, "%s", private_key_name);
-	} else {
-		b = BIO_new_file(private_key_name, "rb");
-		ERR(!b, "%s", private_key_name);
-		private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, NULL);
-		ERR(!private_key, "%s", private_key_name);
-		BIO_free(b);
-	}
-
-	b = BIO_new_file(x509_name, "rb");
-	ERR(!b, "%s", x509_name);
-	x509 = d2i_X509_bio(b, NULL); /* Binary encoded X.509 */
-	if (!x509) {
-		ERR(BIO_reset(b) != 1, "%s", x509_name);
-		x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); /* PEM encoded X.509 */
-		if (x509)
-			drain_openssl_errors();
-	}
-	BIO_free(b);
-	ERR(!x509, "%s", x509_name);
+	/* Open the module file */
+	bm = BIO_new_file(module_name, "rb");
+	ERR(!bm, "%s", module_name);
 
-	/* Open the destination file now so that we can shovel the module data
-	 * across as we read it.
-	 */
-	if (!sign_only) {
-		bd = BIO_new_file(dest_name, "wb");
-		ERR(!bd, "%s", dest_name);
-	}
+	if (!raw_sig) {
 
-	/* Digest the module data. */
-	OpenSSL_add_all_digests();
-	display_openssl_errors(__LINE__);
-	digest_algo = EVP_get_digestbyname(hash_algo);
-	ERR(!digest_algo, "EVP_get_digestbyname");
+		/* Read the private key and the X.509 cert the PKCS#7 message
+		 * will point to.
+		 */
+		private_key = read_private_key(private_key_name);
+		x509 = read_x509(x509_name);
 
-	bm = BIO_new_file(module_name, "rb");
-	ERR(!bm, "%s", module_name);
+		/* Digest the module data. */
+		OpenSSL_add_all_digests();
+		display_openssl_errors(__LINE__);
+		digest_algo = EVP_get_digestbyname(hash_algo);
+		ERR(!digest_algo, "EVP_get_digestbyname");
 
 #ifndef USE_PKCS7
-	/* Load the signature message from the digest buffer. */
-	cms = CMS_sign(NULL, NULL, NULL, NULL,
-		       CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY | CMS_DETACHED | CMS_STREAM);
-	ERR(!cms, "CMS_sign");
-
-	ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
-			     CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP |
-			     use_keyid | use_signed_attrs),
-	    "CMS_add1_signer");
-	ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0,
-	    "CMS_final");
+		/* Load the signature message from the digest buffer. */
+		cms = CMS_sign(NULL, NULL, NULL, NULL,
+			       CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY |
+			       CMS_DETACHED | CMS_STREAM);
+		ERR(!cms, "CMS_sign");
+
+		ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
+				     CMS_NOCERTS | CMS_BINARY |
+				     CMS_NOSMIMECAP | use_keyid |
+				     use_signed_attrs),
+		    "CMS_add1_signer");
+		ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0,
+		    "CMS_final");
 
 #else
-	pkcs7 = PKCS7_sign(x509, private_key, NULL, bm,
-			   PKCS7_NOCERTS | PKCS7_BINARY |
-			   PKCS7_DETACHED | use_signed_attrs);
-	ERR(!pkcs7, "PKCS7_sign");
+		pkcs7 = PKCS7_sign(x509, private_key, NULL, bm,
+				   PKCS7_NOCERTS | PKCS7_BINARY |
+				   PKCS7_DETACHED | use_signed_attrs);
+		ERR(!pkcs7, "PKCS7_sign");
 #endif
+	}
 
-	if (save_sig) {
+	if (!raw_sig && save_sig) {
 		char *sig_file_name;
+		BIO *b;
 
 		ERR(asprintf(&sig_file_name, "%s.p7s", module_name) < 0,
 		    "asprintf");
@@ -291,8 +325,16 @@ int main(int argc, char **argv)
 		BIO_free(b);
 	}
 
-	if (sign_only)
+	if (!raw_sig && sign_only) {
+		BIO_free(bm);
 		return 0;
+	}
+
+	/* Open the destination file now so that we can shovel the module data
+	 * across as we read it.
+	 */
+	bd = BIO_new_file(dest_name, "wb");
+	ERR(!bd, "%s", dest_name);
 
 	/* Append the marker and the PKCS#7 message to the destination file */
 	ERR(BIO_reset(bm) < 0, "%s", module_name);
@@ -300,14 +342,29 @@ int main(int argc, char **argv)
 	       n > 0) {
 		ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name);
 	}
+	BIO_free(bm);
 	ERR(n < 0, "%s", module_name);
 	module_size = BIO_number_written(bd);
 
+	if (!raw_sig) {
 #ifndef USE_PKCS7
-	ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name);
+		ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name);
 #else
-	ERR(i2d_PKCS7_bio(bd, pkcs7) < 0, "%s", dest_name);
+		ERR(i2d_PKCS7_bio(bd, pkcs7) < 0, "%s", dest_name);
 #endif
+	} else {
+		BIO *b;
+
+		/* Read the raw signature file and write the data to the
+		 * destination file
+		 */
+		b = BIO_new_file(raw_sig_name, "rb");
+		ERR(!b, "%s", raw_sig_name);
+		while ((n = BIO_read(b, buf, sizeof(buf))), n > 0)
+			ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name);
+		BIO_free(b);
+	}
+
 	sig_size = BIO_number_written(bd) - module_size;
 	sig_info.sig_len = htonl(sig_size);
 	ERR(BIO_write(bd, &sig_info, sizeof(sig_info)) < 0, "%s", dest_name);
-- 
2.1.4

Powered by blists - more mailing lists