source: EcnlProtoTool/trunk/mrbgems/mruby-tls-openssl/src/openssl.c@ 331

Last change on this file since 331 was 331, checked in by coas-nagasima, 6 years ago

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc
File size: 15.0 KB
Line 
1#include <sys/types.h>
2#ifndef _WIN32
3#include <sys/socket.h>
4#include <netinet/in.h>
5#include <arpa/inet.h>
6#else
7#include <win32netcompat.h>
8#endif
9#include <sys/time.h>
10#include <ctype.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <unistd.h>
15
16#include <openssl/bio.h>
17#include <openssl/err.h>
18#include <openssl/opensslv.h>
19#include <openssl/rand.h>
20#include <openssl/ssl.h>
21#include <openssl/x509.h>
22#include <openssl/x509v3.h>
23#include <openssl/x509_vfy.h>
24
25#include "mruby.h"
26#include "mruby/class.h"
27#include "mruby/data.h"
28#include "mruby/string.h"
29
30/*
31 * OpenSSL::SSL_CTX
32 */
33
34struct mrb_openssl_ssl_ctx {
35 SSL_CTX *ctx;
36};
37
38static void mrb_openssl_ssl_ctx_free(mrb_state *mrb, void *ptr);
39
40const static struct mrb_data_type mrb_openssl_ssl_ctx_type = { "OpenSSL::SSL_CTX", mrb_openssl_ssl_ctx_free };
41
42static void
43mrb_openssl_ssl_ctx_free(mrb_state *mrb, void *ptr)
44{
45 struct mrb_openssl_ssl_ctx *mrb_ctx = ptr;
46 if (mrb_ctx->ctx != NULL) {
47 SSL_CTX_free(mrb_ctx->ctx);
48 }
49 mrb_free(mrb, ptr);
50}
51
52static const SSL_METHOD *
53method_str_to_val(mrb_state *mrb, mrb_value str)
54{
55 const char *cp;
56 size_t len;
57
58 cp = RSTRING_PTR(str);
59 len = RSTRING_LEN(str);
60 if (strncmp("TLSv1.0", cp, len) == 0) {
61 return TLSv1_client_method();
62 } else if (strncmp("TLSv1.1", cp, len) == 0) {
63 return TLSv1_1_client_method();
64 } else if (strncmp("TLSv1.2", cp, len) == 0) {
65 return TLSv1_2_client_method();
66 } else if (strncmp("any", cp, len) == 0) {
67 return SSLv23_client_method();
68 }
69
70 mrb_raisef(mrb, E_RUNTIME_ERROR, "TLS/SSL version %S is not supported", str);
71 return NULL;
72}
73
74static mrb_value
75mrb_openssl_ssl_ctx_init(mrb_state *mrb, mrb_value self)
76{
77 struct mrb_openssl_ssl_ctx *mrb_ctx;
78 SSL_CTX *ctx;
79 const SSL_METHOD *method;
80 mrb_value str;
81
82 mrb_get_args(mrb, "S", &str);
83 method = method_str_to_val(mrb, str);
84
85 ctx = SSL_CTX_new(method);
86 if (ctx == NULL) {
87 mrb_raise(mrb, E_RUNTIME_ERROR, "SSL_CTX_new failed");
88 }
89
90 mrb_ctx = (struct mrb_openssl_ssl_ctx *)mrb_malloc(mrb, sizeof(*mrb_ctx));
91 mrb_ctx->ctx = ctx;
92 DATA_TYPE(self) = &mrb_openssl_ssl_ctx_type;
93 DATA_PTR(self) = mrb_ctx;
94 return self;
95}
96
97static mrb_value
98mrb_openssl_ssl_ctx_load_verify_locations(mrb_state *mrb, mrb_value self)
99{
100 struct mrb_openssl_ssl_ctx *mrb_ctx;
101 mrb_value str;
102 char *cp;
103
104 mrb_ctx = mrb_data_get_ptr(mrb, self, &mrb_openssl_ssl_ctx_type);
105 mrb_get_args(mrb, "S", &str);
106 cp = mrb_str_to_cstr(mrb, str);
107 if (SSL_CTX_load_verify_locations(mrb_ctx->ctx, cp, NULL) != 1) {
108 mrb_raisef(mrb, E_RUNTIME_ERROR, "SSL_CTX_load_verify_locations(\"%S\") failed", str);
109 }
110 return self;
111}
112
113static mrb_value
114mrb_openssl_ssl_ctx_set_alpn_protos(mrb_state *mrb, mrb_value self)
115{
116#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
117 struct mrb_openssl_ssl_ctx *mrb_ctx;
118 mrb_value buf, str;
119 mrb_int len;
120 unsigned char *cp;
121
122 mrb_ctx = mrb_data_get_ptr(mrb, self, &mrb_openssl_ssl_ctx_type);
123 mrb_get_args(mrb, "S", &str);
124 len = RSTRING_LEN(str);
125 buf = mrb_str_buf_new(mrb, len+1);
126 cp = (unsigned char *)RSTRING_PTR(buf);
127 *cp = (unsigned char)len; /* XXX len must be <= 255 */
128 memcpy(cp+1, RSTRING_PTR(str), len);
129 if (SSL_CTX_set_alpn_protos(mrb_ctx->ctx, cp, len+1) != 0) {
130 mrb_raise(mrb, E_RUNTIME_ERROR, "SSL_CTX_set_alpn_protos() failed");
131 }
132 return self;
133#else
134 mrb_raise(mrb, E_NOTIMP_ERROR, "SSL_CTX_set_alpn_protos() is not available");
135 return self;
136#endif
137}
138
139static mrb_value
140mrb_openssl_ssl_ctx_set_verify_depth(mrb_state *mrb, mrb_value self)
141{
142 struct mrb_openssl_ssl_ctx *mrb_ctx;
143 mrb_int n;
144
145 mrb_ctx = mrb_data_get_ptr(mrb, self, &mrb_openssl_ssl_ctx_type);
146 mrb_get_args(mrb, "i", &n);
147 SSL_CTX_set_verify_depth(mrb_ctx->ctx, n);
148 return self;
149}
150
151static int
152ssl_ctx_verify_callback_ignorevalidity(int ok, X509_STORE_CTX *ctx)
153{
154 if (ok == 0) {
155 int ecode = X509_STORE_CTX_get_error(ctx);
156 if (ecode == X509_V_ERR_CERT_NOT_YET_VALID || ecode == X509_V_ERR_CERT_HAS_EXPIRED) {
157 X509_STORE_CTX_set_error(ctx, X509_V_OK);
158 return 1;
159 }
160 }
161 return ok;
162}
163
164static mrb_value
165mrb_openssl_ssl_ctx_set_verify(mrb_state *mrb, mrb_value self)
166{
167 struct mrb_openssl_ssl_ctx *mrb_ctx;
168 mrb_value b = mrb_nil_value();
169 mrb_get_args(mrb, "|o", &b);
170 mrb_ctx = mrb_data_get_ptr(mrb, self, &mrb_openssl_ssl_ctx_type);
171 if (mrb_bool(b)) { // :ignore_certificate_validity
172 SSL_CTX_set_verify(mrb_ctx->ctx, SSL_VERIFY_PEER, ssl_ctx_verify_callback_ignorevalidity);
173 } else {
174 SSL_CTX_set_verify(mrb_ctx->ctx, SSL_VERIFY_PEER, NULL);
175 }
176 return self;
177}
178
179/*
180 * OpenSSL::SSL
181 */
182
183struct mrb_openssl_ssl {
184 SSL *ssl;
185};
186static void mrb_openssl_ssl_free(mrb_state *mrb, void *ptr);
187
188const static struct mrb_data_type mrb_openssl_ssl_type = { "OpenSSL::SSL", mrb_openssl_ssl_free };
189
190static void
191mrb_openssl_ssl_free(mrb_state *mrb, void *ptr)
192{
193 struct mrb_openssl_ssl *mrb_ssl = ptr;
194 if (mrb_ssl->ssl != NULL) {
195 SSL_free(mrb_ssl->ssl);
196 }
197 mrb_free(mrb, ptr);
198}
199
200int
201mrb_openssl_match_dns_id(const char *ref_id, const char *pr_id)
202{
203 const char *dotp, *pr_domain, *ref_domain;
204
205 if (strchr(pr_id, '*') == NULL) {
206 /* no wildcard characters - it's easy */
207 return strcasecmp(ref_id, pr_id) == 0;
208 }
209
210 /* Note: we don't support partial matching like "f*.com". */
211
212 if (pr_id[0] != '*' || pr_id[1] != '.') {
213 /* reject any wildcard identifier DOES NOT start with "*." */
214 return 0;
215 }
216
217 /* where pr_id = "*.example.com", pr_domain points to "example.com" */
218 pr_domain = pr_id + 2;
219
220 if (strchr(pr_domain, '*') != NULL) {
221 /* reject multiple wildcard characters (e.g. "*.*.com", "*.example.*") */
222 return 0;
223 }
224
225 /* where pr_domain = "example.com", dotp points to ".com" */
226 dotp = strchr(pr_domain, '.');
227 if (dotp == NULL) {
228 /* reject "*.tld" and "*." */
229 return 0;
230 }
231
232 if (! isalnum(dotp[1])) {
233 /* reject invalid domain name (e.g. "*.com.", "*.net..", "*.foo.-org") */
234 return 0;
235 }
236
237 ref_domain = strchr(ref_id, '.');
238 if (ref_domain == NULL) {
239 /* if ref_id has no dot, it never matches */
240 return 0;
241 }
242 ref_domain++;
243
244 return strcasecmp(pr_domain, ref_domain) == 0;
245}
246
247static mrb_value
248mrb_openssl_ssl_check_identity(mrb_state *mrb, mrb_value self)
249{
250 struct mrb_openssl_ssl *mrb_ssl;
251 ASN1_STRING *as;
252 GENERAL_NAME *name;
253 STACK_OF(GENERAL_NAME) *altnames;
254 X509 *cert;
255 X509_NAME *subj;
256 int addrlen, cplen, i, j, n, ok;
257 char addrbuf[16];
258 const char *cp, *idstr;
259 mrb_value id;
260
261 mrb_ssl = mrb_data_get_ptr(mrb, self, &mrb_openssl_ssl_type);
262 mrb_get_args(mrb, "S", &id);
263 idstr = mrb_str_to_cstr(mrb, id);
264
265 cert = SSL_get_peer_certificate(mrb_ssl->ssl);
266 if (cert == NULL) {
267 mrb_raise(mrb, E_RUNTIME_ERROR, "SSL_get_peer_certificate() failed");
268 }
269
270 if (inet_pton(AF_INET, idstr, addrbuf) == 1) {
271 addrlen = 4;
272 } else if (inet_pton(AF_INET6, idstr, addrbuf) == 1) {
273 addrlen = 16;
274 } else {
275 addrlen = -1;
276 }
277
278 altnames = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
279 if (altnames != NULL) {
280 ok = -1;
281
282 n = sk_GENERAL_NAME_num(altnames);
283 for (i = 0; i < n; i++) {
284 name = sk_GENERAL_NAME_value(altnames, i);
285 if (addrlen == -1 && name->type == GEN_DNS) {
286 ok = 0;
287 cp = (const char *)ASN1_STRING_data(name->d.ia5);
288 cplen = ASN1_STRING_length(name->d.ia5);
289 if (strlen(cp) != cplen) {
290 /* contains NUL character! it should be a malicious certificate. */
291 ok = 0;
292 break;
293 }
294 if (mrb_openssl_match_dns_id(idstr, cp)) {
295 ok = 1;
296 break;
297 }
298 } else if (addrlen != -1 && name->type == GEN_IPADD) {
299 ok = 0;
300 cp = (const char *)ASN1_STRING_data(name->d.iPAddress);
301 cplen = ASN1_STRING_length(name->d.iPAddress);
302 if (cplen == addrlen && memcmp(cp, addrbuf, cplen) == 0) {
303 ok = 1;
304 break;
305 }
306 }
307 }
308 sk_GENERAL_NAME_free(altnames);
309
310 if (ok == 1) {
311 X509_free(cert);
312 return mrb_true_value();
313 } else if (ok == 0) {
314 X509_free(cert);
315 if (addrlen == -1) {
316 mrb_raisef(mrb, E_RUNTIME_ERROR, "dNSName of server certificate does not match \"%S\"", id);
317 }
318 else {
319 mrb_raisef(mrb, E_RUNTIME_ERROR, "iPAddress of server certificate does not match \"%S\"", id);
320 }
321 }
322 }
323
324 if (addrlen != -1) {
325 X509_free(cert);
326 mrb_raise(mrb, E_RUNTIME_ERROR, "identity is an IP address but server certificate does not have iPAddress");
327 }
328
329 subj = X509_get_subject_name(cert);
330 if (subj == NULL) {
331 X509_free(cert);
332 mrb_raise(mrb, E_RUNTIME_ERROR, "server certificate has neither subjectAltName nor subjectName");
333 }
334
335 j = -1;
336 do {
337 i = j;
338 j = X509_NAME_get_index_by_NID(subj, NID_commonName, i);
339 } while (j != -1);
340 if (i == -1) {
341 X509_free(cert);
342 mrb_raise(mrb, E_RUNTIME_ERROR, "server certificate has no commonName");
343 }
344
345 as = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subj, i));
346 if (as == NULL) {
347 X509_free(cert);
348 mrb_raise(mrb, E_RUNTIME_ERROR, "X509_NAME_ENTRY_get_data failed");
349 }
350 cp = (const char *)ASN1_STRING_data(as);
351 cplen = ASN1_STRING_length(as);
352 if (strlen(cp) != cplen) {
353 X509_free(cert);
354 mrb_raise(mrb, E_RUNTIME_ERROR, "CN includes NUL char!");
355 }
356
357 if (! mrb_openssl_match_dns_id(idstr, cp)) {
358 char buf[128];
359 snprintf(buf, sizeof(buf), "CN differs from Host: CN=%s, Host=%s", cp, idstr);
360 X509_free(cert);
361 mrb_raise(mrb, E_RUNTIME_ERROR, buf);
362 }
363
364 X509_free(cert);
365 return mrb_true_value();
366}
367
368static mrb_value
369mrb_openssl_ssl_connect(mrb_state *mrb, mrb_value self)
370{
371 struct mrb_openssl_ssl *mrb_ssl;
372 int ret;
373
374 mrb_ssl = mrb_data_get_ptr(mrb, self, &mrb_openssl_ssl_type);
375 ret = SSL_connect(mrb_ssl->ssl);
376 if (ret != 1) {
377 mrb_value reason;
378 unsigned long e, ecode = 0;
379 long result;
380 while ((e = ERR_get_error()) != 0) {
381 ecode = e;
382 }
383 reason = mrb_str_new_cstr(mrb, ERR_reason_error_string(ecode));
384
385 result = SSL_get_verify_result(mrb_ssl->ssl);
386 if (result != X509_V_OK) {
387 mrb_str_cat_cstr(mrb, reason, ": ");
388 mrb_str_cat_cstr(mrb, reason, X509_verify_cert_error_string(result));
389 }
390
391 mrb_raisef(mrb, E_RUNTIME_ERROR, "SSL_connect() failed: %S", reason);
392 }
393 return self;
394}
395
396static mrb_value
397mrb_openssl_ssl_get_verify_result(mrb_state *mrb, mrb_value self)
398{
399 struct mrb_openssl_ssl *mrb_ssl;
400 long result;
401
402 mrb_ssl = mrb_data_get_ptr(mrb, self, &mrb_openssl_ssl_type);
403 result = SSL_get_verify_result(mrb_ssl->ssl);
404 if (result != X509_V_OK) {
405 mrb_raise(mrb, E_RUNTIME_ERROR, "certificate verification error");
406 }
407 return mrb_true_value();
408}
409
410static mrb_value
411mrb_openssl_ssl_set_fd(mrb_state *mrb, mrb_value self)
412{
413 struct mrb_openssl_ssl *mrb_ssl;
414 mrb_int fd;
415
416 mrb_ssl = mrb_data_get_ptr(mrb, self, &mrb_openssl_ssl_type);
417 mrb_get_args(mrb, "i", &fd);
418 if (SSL_set_fd(mrb_ssl->ssl, fd) == 0) {
419 mrb_raisef(mrb, E_RUNTIME_ERROR, "SSL_set_fd(%S) failed", mrb_fixnum_value(fd));
420 }
421 return self;
422}
423
424static mrb_value
425mrb_openssl_ssl_set_tlsext_host_name(mrb_state *mrb, mrb_value self)
426{
427 struct mrb_openssl_ssl *mrb_ssl;
428 mrb_value str;
429 char *cp;
430
431 mrb_ssl = mrb_data_get_ptr(mrb, self, &mrb_openssl_ssl_type);
432 mrb_get_args(mrb, "S", &str);
433 cp = mrb_str_to_cstr(mrb, str);
434 if (SSL_set_tlsext_host_name(mrb_ssl->ssl, cp) == 0) {
435 mrb_raisef(mrb, E_RUNTIME_ERROR, "SSL_set_tlsext_host_name(\"%S\") failed", str);
436 }
437 return self;
438}
439
440static mrb_value
441mrb_openssl_ssl_read(mrb_state *mrb, mrb_value self)
442{
443 struct mrb_openssl_ssl *mrb_ssl;
444 mrb_value buf;
445 mrb_int len = 0;
446 size_t bufsize;
447 int n;
448
449 mrb_ssl = mrb_data_get_ptr(mrb, self, &mrb_openssl_ssl_type);
450 mrb_get_args(mrb, "|i", &len);
451
452 if (len > 0) {
453 bufsize = len;
454 } else {
455 bufsize = 16384; /* TLS record size */
456 }
457 buf = mrb_str_buf_new(mrb, bufsize);
458 n = SSL_read(mrb_ssl->ssl, RSTRING_PTR(buf), bufsize);
459 if (n == 0) {
460 return mrb_nil_value();
461 } else if (n < 0) {
462 mrb_raisef(mrb, E_RUNTIME_ERROR, "SSL_read returns %S", mrb_fixnum_value(n));
463 }
464 mrb_str_resize(mrb, buf, n);
465 return buf;
466}
467
468static mrb_value
469mrb_openssl_ssl_shutdown(mrb_state *mrb, mrb_value self)
470{
471 struct mrb_openssl_ssl *mrb_ssl;
472 int r;
473
474 mrb_ssl = mrb_data_get_ptr(mrb, self, &mrb_openssl_ssl_type);
475 r = SSL_shutdown(mrb_ssl->ssl);
476 if (r < 0) {
477 mrb_raisef(mrb, E_RUNTIME_ERROR, "SSL_shutdown returns %S", mrb_fixnum_value(r));
478 }
479 return mrb_fixnum_value(r);
480}
481
482static mrb_value
483mrb_openssl_ssl_write(mrb_state *mrb, mrb_value self)
484{
485 struct mrb_openssl_ssl *mrb_ssl;
486 mrb_int len;
487 int n;
488 char *cp;
489
490 mrb_ssl = mrb_data_get_ptr(mrb, self, &mrb_openssl_ssl_type);
491 mrb_get_args(mrb, "s", &cp, &len);
492 n = SSL_write(mrb_ssl->ssl, cp, len);
493 return mrb_fixnum_value(n);
494}
495
496static mrb_value
497mrb_openssl_ssl_init(mrb_state *mrb, mrb_value self)
498{
499 struct mrb_openssl_ssl *mrb_ssl;
500 struct mrb_openssl_ssl_ctx *mrb_ctx;
501 SSL *ssl;
502 mrb_value v_ctx;
503
504 mrb_get_args(mrb, "o", &v_ctx);
505 mrb_ctx = mrb_data_get_ptr(mrb, v_ctx, &mrb_openssl_ssl_ctx_type);
506
507 mrb_ssl = (struct mrb_openssl_ssl *)mrb_malloc(mrb, sizeof(*mrb_ssl));
508
509 ssl = SSL_new(mrb_ctx->ctx);
510 if (ssl == NULL) {
511 mrb_free(mrb, mrb_ssl);
512 mrb_raise(mrb, E_RUNTIME_ERROR, "SSL_new failed");
513 }
514
515 mrb_ssl->ssl = ssl;
516 DATA_TYPE(self) = &mrb_openssl_ssl_type;
517 DATA_PTR(self) = mrb_ssl;
518 return self;
519}
520
521void
522mrb_mruby_tls_openssl_gem_init(mrb_state *mrb)
523{
524 struct RClass *c_ctx, *c_ssl, *m;
525
526 SSL_load_error_strings();
527 SSL_library_init();
528
529 m = mrb_define_module(mrb, "OpenSSL");
530
531 c_ssl = mrb_define_class_under(mrb, m, "SSL", mrb->object_class);
532 MRB_SET_INSTANCE_TT(c_ssl, MRB_TT_DATA);
533 mrb_define_method(mrb, c_ssl, "initialize", mrb_openssl_ssl_init, MRB_ARGS_NONE());
534 mrb_define_method(mrb, c_ssl, "check_identity", mrb_openssl_ssl_check_identity, MRB_ARGS_REQ(1));
535 mrb_define_method(mrb, c_ssl, "connect", mrb_openssl_ssl_connect, MRB_ARGS_NONE());
536 mrb_define_method(mrb, c_ssl, "get_verify_result", mrb_openssl_ssl_get_verify_result, MRB_ARGS_NONE());
537 mrb_define_method(mrb, c_ssl, "read", mrb_openssl_ssl_read, MRB_ARGS_OPT(2));
538 mrb_define_method(mrb, c_ssl, "set_fd", mrb_openssl_ssl_set_fd, MRB_ARGS_REQ(1));
539 mrb_define_method(mrb, c_ssl, "set_tlsext_host_name", mrb_openssl_ssl_set_tlsext_host_name, MRB_ARGS_REQ(1));
540 mrb_define_method(mrb, c_ssl, "shutdown", mrb_openssl_ssl_shutdown, MRB_ARGS_NONE());
541 mrb_define_method(mrb, c_ssl, "write", mrb_openssl_ssl_write, MRB_ARGS_REQ(1));
542
543 c_ctx = mrb_define_class_under(mrb, m, "SSL_CTX", mrb->object_class);
544 MRB_SET_INSTANCE_TT(c_ctx, MRB_TT_DATA);
545 mrb_define_method(mrb, c_ctx, "initialize", mrb_openssl_ssl_ctx_init, MRB_ARGS_NONE());
546 mrb_define_method(mrb, c_ctx, "load_verify_locations", mrb_openssl_ssl_ctx_load_verify_locations, MRB_ARGS_REQ(1));
547 mrb_define_method(mrb, c_ctx, "set_alpn_protos", mrb_openssl_ssl_ctx_set_alpn_protos, MRB_ARGS_REQ(1));
548 mrb_define_method(mrb, c_ctx, "set_verify", mrb_openssl_ssl_ctx_set_verify, MRB_ARGS_NONE());
549 mrb_define_method(mrb, c_ctx, "set_verify_depth", mrb_openssl_ssl_ctx_set_verify_depth, MRB_ARGS_REQ(1));
550}
551
552void
553mrb_mruby_tls_openssl_gem_final(mrb_state *mrb)
554{
555}
Note: See TracBrowser for help on using the repository browser.