1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // Sandboxed version of simplessl.c
16 // HTTPS GET request
17
18 #include <cstdlib>
19
20 #include "../curl_util.h" // NOLINT(build/include)
21 #include "../sandbox.h" // NOLINT(build/include)
22 #include "curl_sapi.sapi.h" // NOLINT(build/include)
23 #include "absl/strings/str_cat.h"
24 #include "sandboxed_api/util/status_macros.h"
25
26 namespace {
27
28 class CurlSapiSandboxEx3 : public curl::CurlSapiSandbox {
29 public:
CurlSapiSandboxEx3(std::string ssl_certificate,std::string ssl_key,std::string ca_certificates)30 CurlSapiSandboxEx3(std::string ssl_certificate, std::string ssl_key,
31 std::string ca_certificates)
32 : ssl_certificate(std::move(ssl_certificate)),
33 ssl_key(std::move(ssl_key)),
34 ca_certificates(std::move(ca_certificates)) {}
35
36 private:
ModifyPolicy(sandbox2::PolicyBuilder *)37 std::unique_ptr<sandbox2::Policy> ModifyPolicy(
38 sandbox2::PolicyBuilder*) override {
39 // Add the syscalls and files missing in CurlSandbox to a new PolicyBuilder
40 auto policy_builder = std::make_unique<sandbox2::PolicyBuilder>();
41 (*policy_builder)
42 .AllowGetPIDs()
43 .AllowGetRandom()
44 .AllowHandleSignals()
45 .AddFile(ssl_certificate)
46 .AddFile(ssl_key)
47 .AddFile(ca_certificates);
48 // Provide the new PolicyBuilder to ModifyPolicy in CurlSandbox
49 return curl::CurlSapiSandbox::ModifyPolicy(policy_builder.get());
50 }
51
52 std::string ssl_certificate;
53 std::string ssl_key;
54 std::string ca_certificates;
55 };
56
Example3(const std::string & ssl_certificate,const std::string & ssl_key,const std::string & ssl_key_password,const std::string & ca_certificates)57 absl::Status Example3(const std::string& ssl_certificate,
58 const std::string& ssl_key,
59 const std::string& ssl_key_password,
60 const std::string& ca_certificates) {
61 // Initialize sandbox2 and sapi
62 CurlSapiSandboxEx3 sandbox(ssl_certificate, ssl_key, ca_certificates);
63 SAPI_RETURN_IF_ERROR(sandbox.Init());
64 curl::CurlApi api(&sandbox);
65
66 int curl_code;
67
68 // Initialize curl (CURL_GLOBAL_DEFAULT = 3)
69 SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_global_init(3l));
70 if (curl_code != 0) {
71 return absl::UnavailableError(absl::StrCat(
72 "curl_global_init failed: ", curl::StrError(&api, curl_code)));
73 }
74
75 // Initialize curl easy handle
76 curl::CURL* curl_handle;
77 SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
78 sapi::v::RemotePtr curl(curl_handle);
79 if (!curl_handle) {
80 return absl::UnavailableError("curl_easy_init failed: Invalid curl handle");
81 }
82
83 // Specify URL to get (using HTTPS)
84 sapi::v::ConstCStr url("https://example.com");
85 SAPI_ASSIGN_OR_RETURN(
86 curl_code,
87 api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL, url.PtrBefore()));
88 if (curl_code != 0) {
89 return absl::UnavailableError(absl::StrCat(
90 "curl_easy_setopt_ptr failed: ", curl::StrError(&api, curl_code)));
91 }
92
93 // Set the SSL certificate type to "PEM"
94 sapi::v::ConstCStr ssl_cert_type("PEM");
95 SAPI_ASSIGN_OR_RETURN(
96 curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLCERTTYPE,
97 ssl_cert_type.PtrBefore()));
98 if (curl_code != 0) {
99 return absl::UnavailableError(absl::StrCat(
100 "curl_easy_setopt_ptr failed: ", curl::StrError(&api, curl_code)));
101 }
102
103 // Set the certificate for client authentication
104 sapi::v::ConstCStr sapi_ssl_certificate(ssl_certificate.c_str());
105 SAPI_ASSIGN_OR_RETURN(
106 curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLCERT,
107 sapi_ssl_certificate.PtrBefore()));
108 if (curl_code != 0) {
109 return absl::UnavailableError(absl::StrCat(
110 "curl_easy_setopt_ptr failed: ", curl::StrError(&api, curl_code)));
111 }
112
113 // Set the private key for client authentication
114 sapi::v::ConstCStr sapi_ssl_key(ssl_key.c_str());
115 SAPI_ASSIGN_OR_RETURN(curl_code,
116 api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLKEY,
117 sapi_ssl_key.PtrBefore()));
118 if (curl_code != 0) {
119 return absl::UnavailableError(absl::StrCat(
120 "curl_easy_setopt_ptr failed: ", curl::StrError(&api, curl_code)));
121 }
122
123 // Set the password used to protect the private key
124 sapi::v::ConstCStr sapi_ssl_key_password(ssl_key_password.c_str());
125 SAPI_ASSIGN_OR_RETURN(
126 curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_KEYPASSWD,
127 sapi_ssl_key_password.PtrBefore()));
128 if (curl_code != 0) {
129 return absl::UnavailableError(absl::StrCat(
130 "curl_easy_setopt_ptr failed: ", curl::StrError(&api, curl_code)));
131 }
132
133 // Set the file with the certificates vaildating the server
134 sapi::v::ConstCStr sapi_ca_certificates(ca_certificates.c_str());
135 SAPI_ASSIGN_OR_RETURN(
136 curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_CAINFO,
137 sapi_ca_certificates.PtrBefore()));
138 if (curl_code != 0) {
139 return absl::UnavailableError(absl::StrCat(
140 "curl_easy_setopt_ptr failed: ", curl::StrError(&api, curl_code)));
141 }
142
143 // Verify the authenticity of the server
144 SAPI_ASSIGN_OR_RETURN(
145 curl_code,
146 api.curl_easy_setopt_long(&curl, curl::CURLOPT_SSL_VERIFYPEER, 1L));
147 if (curl_code != 0) {
148 return absl::UnavailableError(absl::StrCat(
149 "curl_easy_setopt_long failed: ", curl::StrError(&api, curl_code)));
150 }
151
152 // Perform the request
153 SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl));
154 if (curl_code != 0) {
155 return absl::UnavailableError(absl::StrCat(
156 "curl_easy_perform failed: ", curl::StrError(&api, curl_code)));
157 }
158
159 // Cleanup curl easy handle
160 SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl));
161
162 // Cleanup curl
163 SAPI_RETURN_IF_ERROR(api.curl_global_cleanup());
164
165 return absl::OkStatus();
166 }
167
168 } // namespace
169
main(int argc,char * argv[])170 int main(int argc, char* argv[]) {
171 gflags::ParseCommandLineFlags(&argc, &argv, true);
172 sapi::InitLogging(argv[0]);
173
174 // Get input parameters (should be absolute paths)
175 if (argc != 5) {
176 LOG(ERROR) << "wrong number of arguments (4 expected)";
177 return EXIT_FAILURE;
178 }
179
180 if (absl::Status status = Example3(argv[1], argv[2], argv[3], argv[4]);
181 !status.ok()) {
182 LOG(ERROR) << "Example3 failed: " << status.ToString();
183 return EXIT_FAILURE;
184 }
185
186 return EXIT_SUCCESS;
187 }
188