shill: CertificateFile: Export multiple PEMs at once

Take an array of hex data and output an array of PEM blocks
to a single file.  This format is useful, for example, for
outputting multiple CA entries to a file at once.

BUG=chromium:249363
TEST=Unit test

Change-Id: Iabfddd22464bbfe6cae300497f187dc8680bfc64
Reviewed-on: https://gerrit.chromium.org/gerrit/58567
Commit-Queue: Paul Stewart <pstew@chromium.org>
Reviewed-by: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/certificate_file.cc b/certificate_file.cc
index dd4fa63..1a91795 100644
--- a/certificate_file.cc
+++ b/certificate_file.cc
@@ -52,6 +52,20 @@
       "%s\n%s%s\n", kPEMHeader, hex_data.c_str(), kPEMFooter));
 }
 
+FilePath CertificateFile::CreatePEMFromStrings(
+    const vector<string> &pem_contents) {
+  vector<string> pem_output;
+  for (const auto &content : pem_contents) {
+    string hex_data = ExtractHexData(content);
+    if (hex_data.empty()) {
+      return FilePath();
+    }
+    pem_output.push_back(StringPrintf(
+      "%s\n%s%s\n", kPEMHeader, hex_data.c_str(), kPEMFooter));
+  }
+  return WriteFile(JoinString(pem_output, ""));
+}
+
 FilePath CertificateFile::CreateDERFromString(const string &pem_contents) {
   string hex_data = ExtractHexData(pem_contents);
   string der_contents;
diff --git a/certificate_file.h b/certificate_file.h
index be9abd7..ad4ed1d 100644
--- a/certificate_file.h
+++ b/certificate_file.h
@@ -6,6 +6,7 @@
 #define SHILL_CERTIFICATE_FILE_H_
 
 #include <string>
+#include <vector>
 
 #include <base/file_path.h>
 
@@ -22,9 +23,11 @@
   explicit CertificateFile(GLib *glib);
   virtual ~CertificateFile();
 
-  // Write out a PEM file from an input string in PEM format.
-  // Returns an empty path on failure.
+  // Write out a PEM file from an input string (or vector of strings)
+  // in PEM format.  Returns an empty path on failure.
   virtual base::FilePath CreatePEMFromString(const std::string &pem_contents);
+  virtual base::FilePath CreatePEMFromStrings(
+      const std::vector<std::string> &pem_contents);
 
   // Write out a DER file from an input string in PEM format.
   // Returns an empty path on failure.
diff --git a/certificate_file_unittest.cc b/certificate_file_unittest.cc
index 86202d0..125dc91 100644
--- a/certificate_file_unittest.cc
+++ b/certificate_file_unittest.cc
@@ -5,6 +5,7 @@
 #include "shill/certificate_file.h"
 
 #include <string>
+#include <vector>
 
 #include <base/file_path.h>
 #include <base/file_util.h>
@@ -17,6 +18,7 @@
 using base::FilePath;
 using base::StringPrintf;
 using std::string;
+using std::vector;
 using testing::_;
 using testing::Return;
 using testing::SetArgumentPointee;
@@ -94,6 +96,27 @@
   EXPECT_TRUE(file_util::PathExists(outfile1));
 }
 
+TEST_F(CertificateFileTest, CreatePEMFromStrings) {
+  // Create a formatted PEM file from the inner HEX data.
+  const vector<string> kPEMVector0{ kPEMData, kPEMData };
+  FilePath outfile0 = certificate_file_.CreatePEMFromStrings(kPEMVector0);
+  EXPECT_FALSE(outfile0.empty());
+  EXPECT_TRUE(file_util::PathExists(outfile0));
+  EXPECT_TRUE(file_util::ContainsPath(certificate_directory_, outfile0));
+  string expected_output = StringPrintf(
+      "%s\n%s%s\n%s\n%s%s\n", GetPEMHeader(), kPEMData, GetPEMFooter(),
+      GetPEMHeader(), kPEMData, GetPEMFooter());
+  string file_string0;
+  EXPECT_TRUE(file_util::ReadFileToString(outfile0, &file_string0));
+  EXPECT_EQ(expected_output, file_string0);
+
+  // Fail to create a PEM file.  Old file should not have been deleted.
+  const vector<string> kPEMVector1{ kPEMData, "" };
+  FilePath outfile1 = certificate_file_.CreatePEMFromStrings(kPEMVector1);
+  EXPECT_TRUE(outfile1.empty());
+  EXPECT_TRUE(file_util::PathExists(outfile0));
+}
+
 TEST_F(CertificateFileTest, CreateDERFromString) {
   // Create a DER file from the inner HEX data.
   const string kPEMString = kPEMData;