[PATCH] add pem-directory-hash extract format

Adam Williamson awilliam at redhat.com
Tue Jan 13 20:52:20 PST 2015


This allows extraction of a directory of standard PEM files
with the OpenSSL hash symlinks; this is a format used by
some popular platforms (Debian's /etc/ssl/certs is in this
form, and OpenSUSE provides it for compatibility).
---
 doc/manual/trust.xml    |  6 +++-
 trust/extract-openssl.c | 76 ++++++++++++++++++++++++++-----------------------
 trust/extract-pem.c     | 46 +++++++++++++++++++++++++-----
 trust/extract.c         | 17 ++++++-----
 trust/extract.h         |  8 ++++++
 trust/test-bundle.c     | 35 +++++++++++++++++++++++
 6 files changed, 137 insertions(+), 51 deletions(-)

diff --git a/doc/manual/trust.xml b/doc/manual/trust.xml
index efb66c1..05f2726 100644
--- a/doc/manual/trust.xml
+++ b/doc/manual/trust.xml
@@ -270,7 +270,11 @@ $ trust extract --format=x509-directory --filter=ca-anchors /path/to/directory
 				</varlistentry>
 				<varlistentry>
 					<term><option>pem-directory</option></term>
-					<listitem><para>Directory PEM files each containing one certifiacte</para></listitem>
+					<listitem><para>Directory of PEM files each containing one certificate</para></listitem>
+				</varlistentry>
+				<varlistentry>
+					<term><option>pem-directory-hash</option></term>
+					<listitem><para>Directory of PEM files each containing one certificate, with hash symlinks</para></listitem>
 				</varlistentry>
 				<varlistentry>
 					<term><option>openssl-bundle</option></term>
diff --git a/trust/extract-openssl.c b/trust/extract-openssl.c
index d622d7a..3271339 100644
--- a/trust/extract-openssl.c
+++ b/trust/extract-openssl.c
@@ -587,6 +587,45 @@ symlink_for_subject_old_hash (p11_enumerate *ex)
 
 #endif /* OS_UNIX */
 
+/*
+ * The OpenSSL style c_rehash stuff
+ *
+ * Different versions of openssl build these hashes differently
+ * so output both of them. Shouldn't cause confusion, because
+ * multiple certificates can hash to the same link anyway,
+ * and this is the reason for the trailing number after the dot.
+ *
+ * The trailing number is incremented p11_save_symlink_in() if it
+ * conflicts with something we've already written out.
+ *
+ * On Windows no symlinks.
+ */
+bool
+p11_openssl_symlink (p11_enumerate *ex,
+                     p11_save_dir *dir,
+                     const char *filename)
+{
+	bool ret = true;
+#ifdef OS_UNIX
+	char *linkname;
+
+	linkname = symlink_for_subject_hash (ex);
+	if (linkname) {
+		ret = p11_save_symlink_in (dir, linkname, ".0", filename);
+		free (linkname);
+	}
+
+	if (ret) {
+		linkname = symlink_for_subject_old_hash (ex);
+		if (linkname) {
+			ret = p11_save_symlink_in (dir, linkname, ".0", filename);
+			free (linkname);
+		}
+	}
+#endif /* OS_UNIX */
+	return ret;
+}
+
 bool
 p11_extract_openssl_directory (p11_enumerate *ex,
                                const char *destination)
@@ -601,10 +640,6 @@ p11_extract_openssl_directory (p11_enumerate *ex,
 	char *name;
 	CK_RV rv;
 
-#ifdef OS_UNIX
-	char *linkname;
-#endif
-
 	dir = p11_save_open_directory (destination, ex->flags);
 	if (dir == NULL)
 		return false;
@@ -637,38 +672,7 @@ p11_extract_openssl_directory (p11_enumerate *ex,
 				if (ret)
 					filename = p11_path_base (path);
 			}
-
-			/*
-			 * The OpenSSL style c_rehash stuff
-			 *
-			 * Different versions of openssl build these hashes differently
-			 * so output both of them. Shouldn't cause confusion, because
-			 * multiple certificates can hash to the same link anyway,
-			 * and this is the reason for the trailing number after the dot.
-			 *
-			 * The trailing number is incremented p11_save_symlink_in() if it
-			 * conflicts with something we've already written out.
-			 *
-			 * On Windows no symlinks.
-			 */
-
-#ifdef OS_UNIX
-			if (ret) {
-				linkname = symlink_for_subject_hash (ex);
-				if (linkname) {
-					ret = p11_save_symlink_in (dir, linkname, ".0", filename);
-					free (linkname);
-				}
-			}
-
-			if (ret) {
-				linkname = symlink_for_subject_old_hash (ex);
-				if (linkname) {
-					ret = p11_save_symlink_in (dir, linkname, ".0", filename);
-					free (linkname);
-				}
-			}
-#endif /* OS_UNIX */
+			ret = p11_openssl_symlink(ex, dir, filename);
 
 			free (filename);
 			free (path);
diff --git a/trust/extract-pem.c b/trust/extract-pem.c
index 1e1c857..6d8c662 100644
--- a/trust/extract-pem.c
+++ b/trust/extract-pem.c
@@ -99,14 +99,17 @@ p11_extract_pem_bundle (p11_enumerate *ex,
 }
 
 bool
-p11_extract_pem_directory (p11_enumerate *ex,
-                           const char *destination)
+_p11_extract_pem_directory (p11_enumerate *ex,
+                           const char *destination,
+                           bool hash)
 {
 	p11_save_file *file;
 	p11_save_dir *dir;
 	p11_buffer buf;
 	bool ret = true;
 	char *filename;
+	char *path;
+	char *name;
 	CK_RV rv;
 
 	dir = p11_save_open_directory (destination, ex->flags);
@@ -121,14 +124,25 @@ p11_extract_pem_directory (p11_enumerate *ex,
 		if (!p11_pem_write (ex->cert_der, ex->cert_len, "CERTIFICATE", &buf))
 			return_val_if_reached (false);
 
-		filename = p11_enumerate_filename (ex);
-		return_val_if_fail (filename != NULL, false);
+		name = p11_enumerate_filename (ex);
+		return_val_if_fail (name != NULL, false);
+
+		path = NULL;
 
-		file = p11_save_open_file_in (dir, filename, ".pem");
-		free (filename);
+		file = p11_save_open_file_in (dir, name, ".pem");
+		ret = p11_save_write (file, buf.data, buf.len);
 
-		ret = p11_save_write_and_finish (file, buf.data, buf.len);
+		if (!p11_save_finish_file (file, &path, ret))
+			ret = false;
 
+		if (ret && hash) {
+			filename = p11_path_base (path);
+			ret = p11_openssl_symlink(ex, dir, filename);
+			free (filename);
+		}
+
+		free (path);
+		free (name);
 		if (!ret)
 			break;
 	}
@@ -143,3 +157,21 @@ p11_extract_pem_directory (p11_enumerate *ex,
 	p11_save_finish_directory (dir, ret);
 	return ret;
 }
+
+bool
+p11_extract_pem_directory (p11_enumerate *ex,
+                           const char *destination)
+{
+	bool ret = true;
+	ret = _p11_extract_pem_directory (ex, destination, false);
+	return ret;
+}
+
+bool
+p11_extract_pem_directory_hash (p11_enumerate *ex,
+                           const char *destination)
+{
+	bool ret = true;
+	ret = _p11_extract_pem_directory (ex, destination, true);
+	return ret;
+}
diff --git a/trust/extract.c b/trust/extract.c
index a008270..80b5e72 100644
--- a/trust/extract.c
+++ b/trust/extract.c
@@ -44,6 +44,7 @@
 #include "pkcs11x.h"
 #include "save.h"
 #include "tool.h"
+#include "digest.h"
 
 #include "p11-kit/iter.h"
 #include "p11-kit/pkcs11.h"
@@ -77,6 +78,7 @@ format_argument (const char *optarg,
 		{ "x509-directory", p11_extract_x509_directory, },
 		{ "pem-bundle", p11_extract_pem_bundle, },
 		{ "pem-directory", p11_extract_pem_directory },
+		{ "pem-directory-hash", p11_extract_pem_directory_hash },
 		{ "java-cacerts", p11_extract_jks_cacerts },
 		{ "openssl-bundle", p11_extract_openssl_bundle },
 		{ "openssl-directory", p11_extract_openssl_directory },
@@ -198,13 +200,14 @@ p11_trust_extract (int argc,
 		},
 		{ opt_format,
 		  "format to extract to\n"
-		  "  x509-file         DER X.509 certificate file\n"
-		  "  x509-directory    directory of X.509 certificates\n"
-		  "  pem-bundle        file containing multiple PEM blocks\n"
-		  "  pem-directory     directory of PEM files\n"
-		  "  openssl-bundle    OpenSSL specific PEM bundle\n"
-		  "  openssl-directory directory of OpenSSL specific files\n"
-		  "  java-cacerts      java keystore cacerts file",
+		  "  x509-file           DER X.509 certificate file\n"
+		  "  x509-directory      directory of X.509 certificates\n"
+		  "  pem-bundle          file containing multiple PEM blocks\n"
+		  "  pem-directory       directory of PEM files\n"
+		  "  pem-directory-hash  directory of PEM files with hash links\n"
+		  "  openssl-bundle      OpenSSL specific PEM bundle\n"
+		  "  openssl-directory   directory of OpenSSL specific files\n"
+		  "  java-cacerts        java keystore cacerts file",
 		  "type"
 		},
 		{ opt_purpose,
diff --git a/trust/extract.h b/trust/extract.h
index ca14238..2664ba0 100644
--- a/trust/extract.h
+++ b/trust/extract.h
@@ -39,6 +39,7 @@
 
 #include "enumerate.h"
 #include "pkcs11.h"
+#include "save.h"
 
 enum {
 	/* These overlap with the flags in save.h, so start higher */
@@ -60,6 +61,9 @@ bool            p11_extract_pem_bundle         (p11_enumerate *ex,
 bool            p11_extract_pem_directory      (p11_enumerate *ex,
                                                 const char *destination);
 
+bool            p11_extract_pem_directory_hash (p11_enumerate *ex,
+                                                const char *destination);
+
 bool            p11_extract_jks_cacerts        (p11_enumerate *ex,
                                                 const char *destination);
 
@@ -75,4 +79,8 @@ int             p11_trust_extract              (int argc,
 int             p11_trust_extract_compat       (int argc,
                                                 char *argv[]);
 
+/* from extract-openssl.c but also used in extract-pem.c */
+bool            p11_openssl_symlink            (p11_enumerate *ex,
+                                                p11_save_dir *dir,
+                                                const char *filename);
 #endif /* P11_EXTRACT_H_ */
diff --git a/trust/test-bundle.c b/trust/test-bundle.c
index a12d8a1..3af7277 100644
--- a/trust/test-bundle.c
+++ b/trust/test-bundle.c
@@ -217,6 +217,39 @@ test_directory_empty (void)
 	test_check_directory (test.directory, (NULL, NULL));
 }
 
+static void
+test_directory_hash (void)
+{
+	bool ret;
+
+	mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs);
+	mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_authority_attrs);
+
+	p11_kit_iter_add_filter (test.ex.iter, certificate_filter, 1);
+	p11_kit_iter_begin_with (test.ex.iter, &test.module, 0, 0);
+
+	/* Yes, this is a race, and why you shouldn't build software as root */
+	if (rmdir (test.directory) < 0)
+		assert_not_reached ();
+
+	ret = p11_extract_pem_directory_hash (&test.ex, test.directory);
+	assert_num_eq (true, ret);
+
+	test_check_directory (test.directory, ("Cacert3_Here.pem", "Cacert3_Here.1.pem",
+#ifdef OS_UNIX
+                                           "e5662767.1", "e5662767.0", "590d426f.1", "590d426f.0",
+#endif
+                                           NULL));
+	test_check_file (test.directory, "Cacert3_Here.pem", SRCDIR "/trust/fixtures/cacert3.pem");
+	test_check_file (test.directory, "Cacert3_Here.1.pem", SRCDIR "/trust/fixtures/cacert3.pem");
+#ifdef OS_UNIX
+	test_check_symlink (test.directory, "e5662767.0", "Cacert3_Here.pem");
+	test_check_symlink (test.directory, "e5662767.1", "Cacert3_Here.1.pem");
+	test_check_symlink (test.directory, "590d426f.0", "Cacert3_Here.pem");
+	test_check_symlink (test.directory, "590d426f.1", "Cacert3_Here.1.pem");
+#endif
+}
+
 int
 main (int argc,
       char *argv[])
@@ -229,9 +262,11 @@ main (int argc,
 	p11_test (test_file_without, "/pem/test_file_without");
 	p11_test (test_directory, "/pem/test_directory");
 	p11_test (test_directory_empty, "/pem/test_directory_empty");
+	p11_test (test_directory_hash, "/pem/test_directory_hash");
 	return p11_test_run (argc, argv);
 }
 
 #include "enumerate.c"
 #include "extract-pem.c"
+#include "extract-openssl.c"
 #include "save.c"
-- 
2.2.1



More information about the p11-glue mailing list