| // Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "shill/certificate_file.h" |
| |
| #include <sys/stat.h> |
| |
| #include <string> |
| #include <vector> |
| |
| #include <base/files/file_util.h> |
| #include <base/strings/string_split.h> |
| #include <base/strings/string_util.h> |
| #include <base/strings/stringprintf.h> |
| |
| #include "shill/logging.h" |
| |
| using base::FilePath; |
| using base::SplitString; |
| using base::StringPrintf; |
| using std::string; |
| using std::vector; |
| |
| namespace shill { |
| |
| namespace Logging { |
| static auto kModuleLogScope = ScopeLogger::kCrypto; |
| static string ObjectID(CertificateFile *c) { return "(certificate_file)"; } |
| } |
| |
| const char CertificateFile::kDefaultRootDirectory[] = |
| RUNDIR "/certificate_export"; |
| const char CertificateFile::kPEMHeader[] = "-----BEGIN CERTIFICATE-----"; |
| const char CertificateFile::kPEMFooter[] = "-----END CERTIFICATE-----"; |
| |
| CertificateFile::CertificateFile() |
| : root_directory_(FilePath(kDefaultRootDirectory)) { |
| SLOG(this, 2) << __func__; |
| } |
| |
| CertificateFile::~CertificateFile() { |
| SLOG(this, 2) << __func__; |
| if (!output_file_.empty()) { |
| base::DeleteFile(output_file_, false); |
| } |
| } |
| |
| 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, "")); |
| } |
| |
| // static |
| string CertificateFile::ExtractHexData(const std::string &pem_data) { |
| bool found_header = false; |
| bool found_footer = false; |
| const bool kCaseSensitive = false; |
| vector<string> input_lines; |
| SplitString(pem_data, '\n', &input_lines); |
| vector<string> output_lines; |
| for (vector<string>::const_iterator it = input_lines.begin(); |
| it != input_lines.end(); ++it) { |
| string line; |
| base::TrimWhitespaceASCII(*it, base::TRIM_ALL, &line); |
| if (StartsWithASCII(line, kPEMHeader, kCaseSensitive)) { |
| if (found_header) { |
| LOG(ERROR) << "Found two PEM headers in a row."; |
| return string(); |
| } else { |
| found_header = true; |
| output_lines.clear(); |
| } |
| } else if (StartsWithASCII(line, kPEMFooter, kCaseSensitive)) { |
| if (!found_header) { |
| LOG(ERROR) << "Found a PEM footer before header."; |
| return string(); |
| } else { |
| found_footer = true; |
| break; |
| } |
| } else if (!line.empty()) { |
| output_lines.push_back(line); |
| } |
| } |
| if (found_header && !found_footer) { |
| LOG(ERROR) << "Found PEM header but no footer."; |
| return string(); |
| } |
| DCHECK_EQ(found_header, found_footer); |
| output_lines.push_back(""); |
| return JoinString(output_lines, "\n"); |
| } |
| |
| FilePath CertificateFile::WriteFile(const string &output_data) { |
| if (!base::DirectoryExists(root_directory_)) { |
| if (!base::CreateDirectory(root_directory_)) { |
| LOG(ERROR) << "Unable to create parent directory " |
| << root_directory_.value(); |
| return FilePath(); |
| } |
| if (chmod(root_directory_.value().c_str(), |
| S_IRWXU | S_IXGRP | S_IRGRP | S_IXOTH | S_IROTH)) { |
| LOG(ERROR) << "Failed to set permissions on " |
| << root_directory_.value(); |
| base::DeleteFile(root_directory_, true); |
| return FilePath(); |
| } |
| } |
| if (!output_file_.empty()) { |
| base::DeleteFile(output_file_, false); |
| output_file_ = FilePath(); |
| } |
| |
| FilePath output_file; |
| if (!base::CreateTemporaryFileInDir(root_directory_, &output_file)) { |
| LOG(ERROR) << "Unable to create output file."; |
| return FilePath(); |
| } |
| |
| size_t written = |
| base::WriteFile(output_file, output_data.c_str(), output_data.length()); |
| if (written != output_data.length()) { |
| LOG(ERROR) << "Unable to write to output file."; |
| return FilePath(); |
| } |
| |
| if (chmod(output_file.value().c_str(), |
| S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) { |
| LOG(ERROR) << "Failed to set permissions on " << output_file.value(); |
| base::DeleteFile(output_file, false); |
| return FilePath(); |
| } |
| output_file_ = output_file; |
| return output_file_; |
| } |
| |
| } // namespace shill |