1 /**
2 * Copyright 2015-2017 DataStax, Inc.
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 "php_driver.h"
18 #include "php_driver_types.h"
19
20 #include <ext/standard/php_filestat.h>
21
22 zend_class_entry *php_driver_ssl_builder_ce = NULL;
23
24 static int
file_get_contents(char * path,char ** output,int * len TSRMLS_DC)25 file_get_contents(char *path, char **output, int *len TSRMLS_DC)
26 {
27 #if PHP_MAJOR_VERSION >= 7
28 zend_string *str;
29 php_stream *stream = php_stream_open_wrapper(path, "rb",
30 USE_PATH|REPORT_ERRORS, NULL);
31 #else
32 php_stream *stream = php_stream_open_wrapper(path, "rb",
33 USE_PATH|REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
34 #endif
35
36 if (!stream) {
37 zend_throw_exception_ex(php_driver_runtime_exception_ce, 0 TSRMLS_CC,
38 "The path '%s' doesn't exist or is not readable", path);
39 return 0;
40 }
41
42 #if PHP_MAJOR_VERSION >= 7
43 str = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0);
44 if (str) {
45 *output = estrndup(str->val, str->len);
46 *len = str->len;
47 zend_string_release(str);
48 } else {
49 php_stream_close(stream);
50 return 0;
51 }
52 #else
53 *len = php_stream_copy_to_mem(stream, output, PHP_STREAM_COPY_ALL, 0);
54 #endif
55
56 php_stream_close(stream);
57 return 1;
58 }
59
PHP_METHOD(SSLOptionsBuilder,build)60 PHP_METHOD(SSLOptionsBuilder, build)
61 {
62 php_driver_ssl *ssl = NULL;
63 int len;
64 char *contents;
65 CassError rc;
66
67 php_driver_ssl_builder *builder = PHP_DRIVER_GET_SSL_BUILDER(getThis());
68
69 object_init_ex(return_value, php_driver_ssl_ce);
70 ssl = PHP_DRIVER_GET_SSL(return_value);
71
72 cass_ssl_set_verify_flags(ssl->ssl, builder->flags);
73
74 if (builder->trusted_certs) {
75 int i;
76 char *path;
77
78 for (i = 0; i < builder->trusted_certs_cnt; i++) {
79 path = builder->trusted_certs[i];
80
81 if (!file_get_contents(path, &contents, &len TSRMLS_CC))
82 return;
83
84 rc = cass_ssl_add_trusted_cert_n(ssl->ssl, contents, len);
85 efree(contents);
86 ASSERT_SUCCESS(rc);
87 }
88 }
89
90 if (builder->client_cert) {
91 if (!file_get_contents(builder->client_cert, &contents, &len TSRMLS_CC))
92 return;
93
94 rc = cass_ssl_set_cert_n(ssl->ssl, contents, len);
95 efree(contents);
96 ASSERT_SUCCESS(rc);
97 }
98
99 if (builder->private_key) {
100 if (!file_get_contents(builder->private_key, &contents, &len TSRMLS_CC))
101 return;
102
103 rc = cass_ssl_set_private_key(ssl->ssl, contents, builder->passphrase);
104 efree(contents);
105 ASSERT_SUCCESS(rc);
106 }
107 }
108
PHP_METHOD(SSLOptionsBuilder,withTrustedCerts)109 PHP_METHOD(SSLOptionsBuilder, withTrustedCerts)
110 {
111 zval readable;
112 php5to7_zval_args args = NULL;
113 int argc = 0, i;
114 php_driver_ssl_builder *builder = NULL;
115
116 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
117 return;
118 }
119
120 for (i = 0; i < argc; i++) {
121 zval *path = PHP5TO7_ZVAL_ARG(args[i]);
122
123 if (Z_TYPE_P(path) != IS_STRING) {
124 throw_invalid_argument(path, "path", "a path to a trusted cert file" TSRMLS_CC);
125 PHP5TO7_MAYBE_EFREE(args);
126 }
127
128 php_stat(Z_STRVAL_P(path), Z_STRLEN_P(path), FS_IS_R, &readable TSRMLS_CC);
129
130 if (PHP5TO7_ZVAL_IS_FALSE_P(&readable)) {
131 zend_throw_exception_ex(php_driver_invalid_argument_exception_ce, 0 TSRMLS_CC,
132 "The path '%s' doesn't exist or is not readable", Z_STRVAL_P(path));
133 PHP5TO7_MAYBE_EFREE(args);
134 return;
135 }
136 }
137
138 builder = PHP_DRIVER_GET_SSL_BUILDER(getThis());
139
140 if (builder->trusted_certs) {
141 for (i = 0; i < builder->trusted_certs_cnt; i++) {
142 efree(builder->trusted_certs[i]);
143 }
144
145 efree(builder->trusted_certs);
146 }
147
148 builder->trusted_certs_cnt = argc;
149 builder->trusted_certs = ecalloc(argc, sizeof(char *));
150
151 for (i = 0; i < argc; i++) {
152 zval *path = PHP5TO7_ZVAL_ARG(args[i]);
153
154 builder->trusted_certs[i] = estrndup(Z_STRVAL_P(path), Z_STRLEN_P(path));
155 }
156
157 PHP5TO7_MAYBE_EFREE(args);
158 RETURN_ZVAL(getThis(), 1, 0);
159 }
160
PHP_METHOD(SSLOptionsBuilder,withVerifyFlags)161 PHP_METHOD(SSLOptionsBuilder, withVerifyFlags)
162 {
163 long flags;
164 php_driver_ssl_builder *builder = NULL;
165
166 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) {
167 return;
168 }
169
170 builder = PHP_DRIVER_GET_SSL_BUILDER(getThis());
171
172 builder->flags = (int) flags;
173
174 RETURN_ZVAL(getThis(), 1, 0);
175 }
176
PHP_METHOD(SSLOptionsBuilder,withClientCert)177 PHP_METHOD(SSLOptionsBuilder, withClientCert)
178 {
179 char *client_cert;
180 php5to7_size client_cert_len;
181 zval readable;
182 php_driver_ssl_builder *builder = NULL;
183
184 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &client_cert, &client_cert_len) == FAILURE) {
185 return;
186 }
187
188 php_stat(client_cert, client_cert_len, FS_IS_R, &readable TSRMLS_CC);
189
190 if (PHP5TO7_ZVAL_IS_FALSE_P(&readable)) {
191 zend_throw_exception_ex(php_driver_invalid_argument_exception_ce, 0 TSRMLS_CC,
192 "The path '%s' doesn't exist or is not readable", client_cert);
193 return;
194 }
195
196 builder = PHP_DRIVER_GET_SSL_BUILDER(getThis());
197
198 if (builder->client_cert)
199 efree(builder->client_cert);
200
201 builder->client_cert = estrndup(client_cert, client_cert_len);
202
203 RETURN_ZVAL(getThis(), 1, 0);
204 }
205
PHP_METHOD(SSLOptionsBuilder,withPrivateKey)206 PHP_METHOD(SSLOptionsBuilder, withPrivateKey)
207 {
208 char *private_key;
209 char *passphrase = NULL;
210 php5to7_size private_key_len, passphrase_len;
211 zval readable;
212 php_driver_ssl_builder *builder = NULL;
213
214 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &private_key, &private_key_len, &passphrase, &passphrase_len) == FAILURE) {
215 return;
216 }
217
218 php_stat(private_key, private_key_len, FS_IS_R, &readable TSRMLS_CC);
219
220 if (PHP5TO7_ZVAL_IS_FALSE_P(&readable)) {
221 zend_throw_exception_ex(php_driver_invalid_argument_exception_ce, 0 TSRMLS_CC,
222 "The path '%s' doesn't exist or is not readable", private_key);
223 return;
224 }
225
226 builder = PHP_DRIVER_GET_SSL_BUILDER(getThis());
227
228 if (builder->private_key)
229 efree(builder->private_key);
230
231 builder->private_key = estrndup(private_key, private_key_len);
232
233 if (builder->passphrase) {
234 efree(builder->passphrase);
235 builder->passphrase = NULL;
236 }
237
238 if (passphrase)
239 builder->passphrase = estrndup(passphrase, passphrase_len);
240
241 RETURN_ZVAL(getThis(), 1, 0);
242 }
243
244 ZEND_BEGIN_ARG_INFO_EX(arginfo_none, 0, ZEND_RETURN_VALUE, 0)
245 ZEND_END_ARG_INFO()
246
247 ZEND_BEGIN_ARG_INFO_EX(arginfo_path, 0, ZEND_RETURN_VALUE, 1)
248 ZEND_ARG_INFO(0, path)
249 ZEND_END_ARG_INFO()
250
251 ZEND_BEGIN_ARG_INFO_EX(arginfo_flags, 0, ZEND_RETURN_VALUE, 1)
252 ZEND_ARG_INFO(0, flags)
253 ZEND_END_ARG_INFO()
254
255 ZEND_BEGIN_ARG_INFO_EX(arginfo_key, 0, ZEND_RETURN_VALUE, 1)
256 ZEND_ARG_INFO(0, path)
257 ZEND_ARG_INFO(0, passphrase)
258 ZEND_END_ARG_INFO()
259
260 static zend_function_entry php_driver_ssl_builder_methods[] = {
261 PHP_ME(SSLOptionsBuilder, build, arginfo_none, ZEND_ACC_PUBLIC)
262 PHP_ME(SSLOptionsBuilder, withTrustedCerts, arginfo_path,
263 ZEND_ACC_PUBLIC)
264 PHP_ME(SSLOptionsBuilder, withVerifyFlags, arginfo_flags,
265 ZEND_ACC_PUBLIC)
266 PHP_ME(SSLOptionsBuilder, withClientCert, arginfo_path,
267 ZEND_ACC_PUBLIC)
268 PHP_ME(SSLOptionsBuilder, withPrivateKey, arginfo_key,
269 ZEND_ACC_PUBLIC)
270 PHP_FE_END
271 };
272
273 static zend_object_handlers php_driver_ssl_builder_handlers;
274
275 static HashTable *
php_driver_ssl_builder_properties(zval * object TSRMLS_DC)276 php_driver_ssl_builder_properties(zval *object TSRMLS_DC)
277 {
278 HashTable *props = zend_std_get_properties(object TSRMLS_CC);
279
280 return props;
281 }
282
283 static int
php_driver_ssl_builder_compare(zval * obj1,zval * obj2 TSRMLS_DC)284 php_driver_ssl_builder_compare(zval *obj1, zval *obj2 TSRMLS_DC)
285 {
286 if (Z_OBJCE_P(obj1) != Z_OBJCE_P(obj2))
287 return 1; /* different classes */
288
289 return Z_OBJ_HANDLE_P(obj1) != Z_OBJ_HANDLE_P(obj1);
290 }
291
292 static void
php_driver_ssl_builder_free(php5to7_zend_object_free * object TSRMLS_DC)293 php_driver_ssl_builder_free(php5to7_zend_object_free *object TSRMLS_DC)
294 {
295 php_driver_ssl_builder *self = PHP5TO7_ZEND_OBJECT_GET(ssl_builder, object);
296
297 if (self->trusted_certs) {
298 int i;
299
300 for (i = 0; i < self->trusted_certs_cnt; i++)
301 efree(self->trusted_certs[i]);
302
303 efree(self->trusted_certs);
304 }
305
306 if (self->client_cert)
307 efree(self->client_cert);
308
309 if (self->private_key)
310 efree(self->private_key);
311
312 if (self->passphrase)
313 efree(self->passphrase);
314
315 zend_object_std_dtor(&self->zval TSRMLS_CC);
316 PHP5TO7_MAYBE_EFREE(self);
317 }
318
319 static php5to7_zend_object
php_driver_ssl_builder_new(zend_class_entry * ce TSRMLS_DC)320 php_driver_ssl_builder_new(zend_class_entry *ce TSRMLS_DC)
321 {
322 php_driver_ssl_builder *self =
323 PHP5TO7_ZEND_OBJECT_ECALLOC(ssl_builder, ce);
324
325 self->flags = 0;
326 self->trusted_certs = NULL;
327 self->trusted_certs_cnt = 0;
328 self->client_cert = NULL;
329 self->private_key = NULL;
330 self->passphrase = NULL;
331
332 PHP5TO7_ZEND_OBJECT_INIT(ssl_builder, self, ce);
333 }
334
php_driver_define_SSLOptionsBuilder(TSRMLS_D)335 void php_driver_define_SSLOptionsBuilder(TSRMLS_D)
336 {
337 zend_class_entry ce;
338
339 INIT_CLASS_ENTRY(ce, PHP_DRIVER_NAMESPACE "\\SSLOptions\\Builder", php_driver_ssl_builder_methods);
340 php_driver_ssl_builder_ce = zend_register_internal_class(&ce TSRMLS_CC);
341 php_driver_ssl_builder_ce->ce_flags |= PHP5TO7_ZEND_ACC_FINAL;
342 php_driver_ssl_builder_ce->create_object = php_driver_ssl_builder_new;
343
344 memcpy(&php_driver_ssl_builder_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
345 php_driver_ssl_builder_handlers.get_properties = php_driver_ssl_builder_properties;
346 php_driver_ssl_builder_handlers.compare_objects = php_driver_ssl_builder_compare;
347 }
348