blob: a7dacce2e79a1a407240f01f69ddeb6f9f131d53 [file] [log] [blame]
Paul Stewart5baebb72013-03-14 11:43:29 -07001// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/certificate_file.h"
6
7#include <sys/stat.h>
8
9#include <string>
10#include <vector>
11
12#include <base/file_util.h>
13#include <base/string_split.h>
14#include <base/string_util.h>
15#include <base/stringprintf.h>
16
Paul Stewart5baebb72013-03-14 11:43:29 -070017#include "shill/logging.h"
18
19using base::FilePath;
20using base::SplitString;
21using base::StringPrintf;
22using std::string;
23using std::vector;
24
25namespace shill {
26
27const char CertificateFile::kDefaultRootDirectory[] =
Paul Stewart78af94c2013-04-17 16:02:06 -070028 RUNDIR "/certificate_export";
Paul Stewart5baebb72013-03-14 11:43:29 -070029const char CertificateFile::kPEMHeader[] = "-----BEGIN CERTIFICATE-----";
30const char CertificateFile::kPEMFooter[] = "-----END CERTIFICATE-----";
31
Paul Stewarteb713e82013-06-28 14:51:54 -070032CertificateFile::CertificateFile()
33 : root_directory_(FilePath(kDefaultRootDirectory)) {
Paul Stewart5baebb72013-03-14 11:43:29 -070034 SLOG(Crypto, 2) << __func__;
35}
36
37CertificateFile::~CertificateFile() {
38 SLOG(Crypto, 2) << __func__;
39 if (!output_file_.empty()) {
40 file_util::Delete(output_file_, false);
41 }
42}
43
Paul Stewarta9fbe5c2013-06-13 11:12:55 -070044FilePath CertificateFile::CreatePEMFromStrings(
45 const vector<string> &pem_contents) {
46 vector<string> pem_output;
47 for (const auto &content : pem_contents) {
48 string hex_data = ExtractHexData(content);
49 if (hex_data.empty()) {
50 return FilePath();
51 }
52 pem_output.push_back(StringPrintf(
53 "%s\n%s%s\n", kPEMHeader, hex_data.c_str(), kPEMFooter));
54 }
55 return WriteFile(JoinString(pem_output, ""));
56}
57
Paul Stewart5baebb72013-03-14 11:43:29 -070058// static
59string CertificateFile::ExtractHexData(const std::string &pem_data) {
60 bool found_header = false;
61 bool found_footer = false;
62 const bool kCaseSensitive = false;
63 vector<string> input_lines;
64 SplitString(pem_data, '\n', &input_lines);
65 vector<string> output_lines;
66 for (vector<string>::const_iterator it = input_lines.begin();
67 it != input_lines.end(); ++it) {
68 string line;
69 TrimWhitespaceASCII(*it, TRIM_ALL, &line);
70 if (StartsWithASCII(line, kPEMHeader, kCaseSensitive)) {
71 if (found_header) {
72 LOG(ERROR) << "Found two PEM headers in a row.";
73 return string();
74 } else {
75 found_header = true;
76 output_lines.clear();
77 }
78 } else if (StartsWithASCII(line, kPEMFooter, kCaseSensitive)) {
79 if (!found_header) {
80 LOG(ERROR) << "Found a PEM footer before header.";
81 return string();
82 } else {
83 found_footer = true;
84 break;
85 }
86 } else if (!line.empty()) {
87 output_lines.push_back(line);
88 }
89 }
90 if (found_header && !found_footer) {
91 LOG(ERROR) << "Found PEM header but no footer.";
92 return string();
93 }
94 DCHECK_EQ(found_header, found_footer);
95 output_lines.push_back("");
96 return JoinString(output_lines, "\n");
97}
98
99FilePath CertificateFile::WriteFile(const string &output_data) {
100 if (!file_util::DirectoryExists(root_directory_)) {
101 if (!file_util::CreateDirectory(root_directory_)) {
102 LOG(ERROR) << "Unable to create parent directory "
103 << root_directory_.value();
104 return FilePath();
105 }
106 if (chmod(root_directory_.value().c_str(),
107 S_IRWXU | S_IXGRP | S_IRGRP | S_IXOTH | S_IROTH)) {
108 LOG(ERROR) << "Failed to set permissions on "
109 << root_directory_.value();
110 file_util::Delete(root_directory_, true);
111 return FilePath();
112 }
113 }
114 if (!output_file_.empty()) {
115 file_util::Delete(output_file_, false);
116 output_file_ = FilePath();
117 }
118
119 FilePath output_file;
120 if (!file_util::CreateTemporaryFileInDir(root_directory_, &output_file)) {
121 LOG(ERROR) << "Unable to create output file.";
122 return FilePath();
123 }
124
125 size_t written =
126 file_util::WriteFile(output_file, output_data.c_str(),
127 output_data.length());
128 if (written != output_data.length()) {
129 LOG(ERROR) << "Unable to write to output file.";
130 return FilePath();
131 }
132
133 if (chmod(output_file.value().c_str(),
134 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) {
135 LOG(ERROR) << "Failed to set permissions on " << output_file.value();
136 file_util::Delete(output_file, false);
137 return FilePath();
138 }
139 output_file_ = output_file;
140 return output_file_;
141}
142
143} // namespace shill