blob: dd4fa632b4bc4127d819287367f43c52f54d160b [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
17#include "shill/glib.h"
18#include "shill/logging.h"
19
20using base::FilePath;
21using base::SplitString;
22using base::StringPrintf;
23using std::string;
24using std::vector;
25
26namespace shill {
27
28const char CertificateFile::kDefaultRootDirectory[] =
Paul Stewart78af94c2013-04-17 16:02:06 -070029 RUNDIR "/certificate_export";
Paul Stewart5baebb72013-03-14 11:43:29 -070030const char CertificateFile::kPEMHeader[] = "-----BEGIN CERTIFICATE-----";
31const char CertificateFile::kPEMFooter[] = "-----END CERTIFICATE-----";
32
33CertificateFile::CertificateFile(GLib *glib)
34 : root_directory_(FilePath(kDefaultRootDirectory)),
35 glib_(glib) {
36 SLOG(Crypto, 2) << __func__;
37}
38
39CertificateFile::~CertificateFile() {
40 SLOG(Crypto, 2) << __func__;
41 if (!output_file_.empty()) {
42 file_util::Delete(output_file_, false);
43 }
44}
45
46FilePath CertificateFile::CreatePEMFromString(const string &pem_contents) {
47 string hex_data = ExtractHexData(pem_contents);
48 if (hex_data.empty()) {
49 return FilePath();
50 }
51 return WriteFile(StringPrintf(
52 "%s\n%s%s\n", kPEMHeader, hex_data.c_str(), kPEMFooter));
53}
54
55FilePath CertificateFile::CreateDERFromString(const string &pem_contents) {
56 string hex_data = ExtractHexData(pem_contents);
Christopher Wiley0f3eab32013-03-21 11:55:41 -070057 string der_contents;
58 if (!glib_->B64Decode(hex_data, &der_contents)) {
Paul Stewart5baebb72013-03-14 11:43:29 -070059 LOG(ERROR) << "Could not decode hex data from input PEM";
Paul Stewart5baebb72013-03-14 11:43:29 -070060 return FilePath();
61 }
62
Paul Stewart5baebb72013-03-14 11:43:29 -070063 return WriteFile(der_contents);
64}
65
66// static
67string CertificateFile::ExtractHexData(const std::string &pem_data) {
68 bool found_header = false;
69 bool found_footer = false;
70 const bool kCaseSensitive = false;
71 vector<string> input_lines;
72 SplitString(pem_data, '\n', &input_lines);
73 vector<string> output_lines;
74 for (vector<string>::const_iterator it = input_lines.begin();
75 it != input_lines.end(); ++it) {
76 string line;
77 TrimWhitespaceASCII(*it, TRIM_ALL, &line);
78 if (StartsWithASCII(line, kPEMHeader, kCaseSensitive)) {
79 if (found_header) {
80 LOG(ERROR) << "Found two PEM headers in a row.";
81 return string();
82 } else {
83 found_header = true;
84 output_lines.clear();
85 }
86 } else if (StartsWithASCII(line, kPEMFooter, kCaseSensitive)) {
87 if (!found_header) {
88 LOG(ERROR) << "Found a PEM footer before header.";
89 return string();
90 } else {
91 found_footer = true;
92 break;
93 }
94 } else if (!line.empty()) {
95 output_lines.push_back(line);
96 }
97 }
98 if (found_header && !found_footer) {
99 LOG(ERROR) << "Found PEM header but no footer.";
100 return string();
101 }
102 DCHECK_EQ(found_header, found_footer);
103 output_lines.push_back("");
104 return JoinString(output_lines, "\n");
105}
106
107FilePath CertificateFile::WriteFile(const string &output_data) {
108 if (!file_util::DirectoryExists(root_directory_)) {
109 if (!file_util::CreateDirectory(root_directory_)) {
110 LOG(ERROR) << "Unable to create parent directory "
111 << root_directory_.value();
112 return FilePath();
113 }
114 if (chmod(root_directory_.value().c_str(),
115 S_IRWXU | S_IXGRP | S_IRGRP | S_IXOTH | S_IROTH)) {
116 LOG(ERROR) << "Failed to set permissions on "
117 << root_directory_.value();
118 file_util::Delete(root_directory_, true);
119 return FilePath();
120 }
121 }
122 if (!output_file_.empty()) {
123 file_util::Delete(output_file_, false);
124 output_file_ = FilePath();
125 }
126
127 FilePath output_file;
128 if (!file_util::CreateTemporaryFileInDir(root_directory_, &output_file)) {
129 LOG(ERROR) << "Unable to create output file.";
130 return FilePath();
131 }
132
133 size_t written =
134 file_util::WriteFile(output_file, output_data.c_str(),
135 output_data.length());
136 if (written != output_data.length()) {
137 LOG(ERROR) << "Unable to write to output file.";
138 return FilePath();
139 }
140
141 if (chmod(output_file.value().c_str(),
142 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) {
143 LOG(ERROR) << "Failed to set permissions on " << output_file.value();
144 file_util::Delete(output_file, false);
145 return FilePath();
146 }
147 output_file_ = output_file;
148 return output_file_;
149}
150
151} // namespace shill