1 // 2 // Copyright (C) 2013 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include "shill/certificate_file.h" 18 19 #include <sys/stat.h> 20 21 #include <string> 22 #include <vector> 23 24 #include <base/files/file_util.h> 25 #include <base/strings/string_split.h> 26 #include <base/strings/string_util.h> 27 #include <base/strings/stringprintf.h> 28 29 #include "shill/logging.h" 30 31 using base::FilePath; 32 using base::SplitString; 33 using base::StringPrintf; 34 using std::string; 35 using std::vector; 36 37 namespace shill { 38 39 namespace Logging { 40 static auto kModuleLogScope = ScopeLogger::kCrypto; 41 static string ObjectID(CertificateFile* c) { return "(certificate_file)"; } 42 } 43 44 const char CertificateFile::kDefaultRootDirectory[] = 45 RUNDIR "/certificate_export"; 46 const char CertificateFile::kPEMHeader[] = "-----BEGIN CERTIFICATE-----"; 47 const char CertificateFile::kPEMFooter[] = "-----END CERTIFICATE-----"; 48 49 CertificateFile::CertificateFile() 50 : root_directory_(FilePath(kDefaultRootDirectory)) { 51 SLOG(this, 2) << __func__; 52 } 53 54 CertificateFile::~CertificateFile() { 55 SLOG(this, 2) << __func__; 56 if (!output_file_.empty()) { 57 base::DeleteFile(output_file_, false); 58 } 59 } 60 61 FilePath CertificateFile::CreatePEMFromStrings( 62 const vector<string>& pem_contents) { 63 vector<string> pem_output; 64 for (const auto& content : pem_contents) { 65 string hex_data = ExtractHexData(content); 66 if (hex_data.empty()) { 67 return FilePath(); 68 } 69 pem_output.push_back(StringPrintf( 70 "%s\n%s%s\n", kPEMHeader, hex_data.c_str(), kPEMFooter)); 71 } 72 return WriteFile(base::JoinString(pem_output, "")); 73 } 74 75 // static 76 string CertificateFile::ExtractHexData(const std::string& pem_data) { 77 bool found_header = false; 78 bool found_footer = false; 79 vector<string> input_lines = SplitString( 80 pem_data, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 81 vector<string> output_lines; 82 for (vector<string>::const_iterator it = input_lines.begin(); 83 it != input_lines.end(); ++it) { 84 string line; 85 base::TrimWhitespaceASCII(*it, base::TRIM_ALL, &line); 86 if (base::StartsWith(line, kPEMHeader, 87 base::CompareCase::INSENSITIVE_ASCII)) { 88 if (found_header) { 89 LOG(ERROR) << "Found two PEM headers in a row."; 90 return string(); 91 } else { 92 found_header = true; 93 output_lines.clear(); 94 } 95 } else if (base::StartsWith(line, kPEMFooter, 96 base::CompareCase::INSENSITIVE_ASCII)) { 97 if (!found_header) { 98 LOG(ERROR) << "Found a PEM footer before header."; 99 return string(); 100 } else { 101 found_footer = true; 102 break; 103 } 104 } else if (!line.empty()) { 105 output_lines.push_back(line); 106 } 107 } 108 if (found_header && !found_footer) { 109 LOG(ERROR) << "Found PEM header but no footer."; 110 return string(); 111 } 112 DCHECK_EQ(found_header, found_footer); 113 output_lines.push_back(""); 114 return base::JoinString(output_lines, "\n"); 115 } 116 117 FilePath CertificateFile::WriteFile(const string& output_data) { 118 if (!base::DirectoryExists(root_directory_)) { 119 if (!base::CreateDirectory(root_directory_)) { 120 LOG(ERROR) << "Unable to create parent directory " 121 << root_directory_.value(); 122 return FilePath(); 123 } 124 if (chmod(root_directory_.value().c_str(), 125 S_IRWXU | S_IXGRP | S_IRGRP | S_IXOTH | S_IROTH)) { 126 LOG(ERROR) << "Failed to set permissions on " 127 << root_directory_.value(); 128 base::DeleteFile(root_directory_, true); 129 return FilePath(); 130 } 131 } 132 if (!output_file_.empty()) { 133 base::DeleteFile(output_file_, false); 134 output_file_ = FilePath(); 135 } 136 137 FilePath output_file; 138 if (!base::CreateTemporaryFileInDir(root_directory_, &output_file)) { 139 LOG(ERROR) << "Unable to create output file."; 140 return FilePath(); 141 } 142 143 size_t written = 144 base::WriteFile(output_file, output_data.c_str(), output_data.length()); 145 if (written != output_data.length()) { 146 LOG(ERROR) << "Unable to write to output file."; 147 return FilePath(); 148 } 149 150 if (chmod(output_file.value().c_str(), 151 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) { 152 LOG(ERROR) << "Failed to set permissions on " << output_file.value(); 153 base::DeleteFile(output_file, false); 154 return FilePath(); 155 } 156 output_file_ = output_file; 157 return output_file_; 158 } 159 160 } // namespace shill 161