| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598 | #include <ctype.h>#include <string.h>#include <stdio.h>#ifdef _WIN32#include <windows.h>#include <wincrypt.h>#endif#ifdef __APPLE__#include <Security/Security.h>#endif#include <caml/mlvalues.h>#include <caml/alloc.h>#include <caml/memory.h>#include <caml/fail.h>#include <caml/callback.h>#include <caml/custom.h>#include "mbedtls/debug.h"#include "mbedtls/error.h"#include "mbedtls/config.h"#include "mbedtls/ssl.h"#include "mbedtls/entropy.h"#include "mbedtls/ctr_drbg.h"#include "mbedtls/certs.h"#include "mbedtls/oid.h"#define PVoid_val(v) (*((void**) Data_custom_val(v)))void debug(void* ctx, int debug_level, const char* file_name, int line, const char* message) {	printf("%s:%i: %s", file_name, line, message);}#define Val_none Val_int(0)static value Val_some(value v) {    CAMLparam1(v);    CAMLlocal1(some);    some = caml_alloc(1, 0);    Store_field(some, 0, v);    CAMLreturn(some);}CAMLprim value ml_mbedtls_strerror(value code) {	CAMLparam1(code);	CAMLlocal1(r);	char buf[128];	mbedtls_strerror(Int_val(code), buf, sizeof(buf));	r = caml_copy_string(buf);	CAMLreturn(r);}// CtrDrbg#define CtrDrbg_val(v) (*((mbedtls_ctr_drbg_context**) Data_custom_val(v)))static void ml_mbedtls_ctr_drbg_finalize(value v) {	mbedtls_ctr_drbg_context* ctr_drbg = CtrDrbg_val(v);	if (ctr_drbg != NULL) {		mbedtls_ctr_drbg_free(ctr_drbg);	}}static struct custom_operations ctr_drbg_ops = {	.identifier  = "ml_ctr_drbg",	.finalize    = ml_mbedtls_ctr_drbg_finalize,	.compare     = custom_compare_default,	.hash        = custom_hash_default,	.serialize   = custom_serialize_default,	.deserialize = custom_deserialize_default,};CAMLprim value ml_mbedtls_ctr_drbg_init(void) {	CAMLparam0();	CAMLlocal1(obj);	obj = caml_alloc_custom(&ctr_drbg_ops, sizeof(mbedtls_ctr_drbg_context*), 0, 1);	mbedtls_ctr_drbg_context* ctr_drbg = malloc(sizeof(mbedtls_ctr_drbg_context));	mbedtls_ctr_drbg_init(ctr_drbg);	CtrDrbg_val(obj) = ctr_drbg;	CAMLreturn(obj);}CAMLprim value ml_mbedtls_ctr_drbg_random(value p_rng, value output, value output_len) {	CAMLparam3(p_rng, output, output_len);	CAMLreturn(Val_int(mbedtls_ctr_drbg_random(CtrDrbg_val(p_rng), String_val(output), Int_val(output_len))));}CAMLprim value ml_mbedtls_ctr_drbg_seed(value ctx, value p_entropy, value custom) {	CAMLparam2(ctx, custom);	CAMLreturn(Val_int(mbedtls_ctr_drbg_seed(CtrDrbg_val(ctx), mbedtls_entropy_func, PVoid_val(p_entropy), NULL, 0)));}// Entropy#define Entropy_val(v) (*((mbedtls_entropy_context**) Data_custom_val(v)))static void ml_mbedtls_entropy_finalize(value v) {	mbedtls_entropy_context* entropy = Entropy_val(v);	if (entropy != NULL) {		mbedtls_entropy_free(entropy);	}}static struct custom_operations entropy_ops = {	.identifier  = "ml_entropy",	.finalize    = ml_mbedtls_entropy_finalize,	.compare     = custom_compare_default,	.hash        = custom_hash_default,	.serialize   = custom_serialize_default,	.deserialize = custom_deserialize_default,};CAMLprim value ml_mbedtls_entropy_init(void) {	CAMLparam0();	CAMLlocal1(obj);	obj = caml_alloc_custom(&entropy_ops, sizeof(mbedtls_entropy_context*), 0, 1);	mbedtls_entropy_context* entropy = malloc(sizeof(mbedtls_entropy_context));	mbedtls_entropy_init(entropy);	Entropy_val(obj) = entropy;	CAMLreturn(obj);}CAMLprim value ml_mbedtls_entropy_func(value data, value output, value len) {	CAMLparam3(data, output, len);	CAMLreturn(Val_int(mbedtls_entropy_func(PVoid_val(data), String_val(output), Int_val(len))));}// Certificate#define X509Crt_val(v) (*((mbedtls_x509_crt**) Data_custom_val(v)))static void ml_mbedtls_x509_crt_finalize(value v) {	mbedtls_x509_crt* x509_crt = X509Crt_val(v);	if (x509_crt != NULL) {		mbedtls_x509_crt_free(x509_crt);	}}static struct custom_operations x509_crt_ops = {	.identifier  = "ml_x509_crt",	.finalize    = ml_mbedtls_x509_crt_finalize,	.compare     = custom_compare_default,	.hash        = custom_hash_default,	.serialize   = custom_serialize_default,	.deserialize = custom_deserialize_default,};CAMLprim value ml_mbedtls_x509_crt_init(void) {	CAMLparam0();	CAMLlocal1(obj);	obj = caml_alloc_custom(&x509_crt_ops, sizeof(mbedtls_x509_crt*), 0, 1);	mbedtls_x509_crt* x509_crt = malloc(sizeof(mbedtls_x509_crt));	mbedtls_x509_crt_init(x509_crt);	X509Crt_val(obj) = x509_crt;	CAMLreturn(obj);}CAMLprim value ml_mbedtls_x509_next(value chain) {	CAMLparam1(chain);	CAMLlocal2(r, obj);	mbedtls_x509_crt* cert = X509Crt_val(chain);	if (cert->next == NULL) {		CAMLreturn(Val_none);	}	obj = caml_alloc_custom(&x509_crt_ops, sizeof(mbedtls_x509_crt*), 0, 1);	X509Crt_val(obj) = cert->next;	CAMLreturn(Val_some(obj));}CAMLprim value ml_mbedtls_x509_crt_parse(value chain, value bytes) {	CAMLparam2(chain, bytes);	const char* buf = String_val(bytes);	int len = caml_string_length(bytes);	CAMLreturn(Val_int(mbedtls_x509_crt_parse(X509Crt_val(chain), buf, len + 1)));}CAMLprim value ml_mbedtls_x509_crt_parse_file(value chain, value path) {	CAMLparam2(chain, path);	CAMLreturn(Val_int(mbedtls_x509_crt_parse_file(X509Crt_val(chain), String_val(path))));}CAMLprim value ml_mbedtls_x509_crt_parse_path(value chain, value path) {	CAMLparam2(chain, path);	CAMLreturn(Val_int(mbedtls_x509_crt_parse_path(X509Crt_val(chain), String_val(path))));}// Certificate Haxe APIvalue caml_string_of_asn1_buf(mbedtls_asn1_buf* dat) {	CAMLparam0();	CAMLlocal1(s);	s = caml_alloc_string(dat->len);	memcpy(String_val(s), dat->p, dat->len);	CAMLreturn(s);}CAMLprim value hx_cert_get_alt_names(value chain) {	CAMLparam1(chain);	CAMLlocal1(obj);	mbedtls_x509_crt* cert = X509Crt_val(chain);	if (cert->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME == 0 || &cert->subject_alt_names == NULL) {		obj = Atom(0);	} else {		mbedtls_asn1_sequence* cur = &cert->subject_alt_names;		int i = 0;		while (cur != NULL) {			++i;			cur = cur->next;		}		obj = caml_alloc(i, 0);		cur = &cert->subject_alt_names;		i = 0;		while (cur != NULL) {			Store_field(obj, i, caml_string_of_asn1_buf(&cur->buf));			++i;			cur = cur->next;		}	}	CAMLreturn(obj);}CAMLprim value hx_cert_get_subject(value chain, value objname) {	CAMLparam2(chain, objname);	mbedtls_x509_name *obj;	mbedtls_x509_crt* cert = X509Crt_val(chain);	const char *oname, *rname;	obj = &cert->subject;	rname = String_val(objname);	while (obj != NULL) {		int r = mbedtls_oid_get_attr_short_name(&obj->oid, &oname);		if (r == 0 && strcmp(oname, rname) == 0) {			CAMLreturn(Val_some(caml_string_of_asn1_buf(&obj->val)));		}		obj = obj->next;	}	CAMLreturn(Val_none);}CAMLprim value hx_cert_get_issuer(value chain, value objname) {	CAMLparam2(chain, objname);	mbedtls_x509_name *obj;	mbedtls_x509_crt* cert = X509Crt_val(chain);	int r;	const char *oname, *rname;	obj = &cert->issuer;	rname = String_val(objname);	while (obj != NULL) {		r = mbedtls_oid_get_attr_short_name(&obj->oid, &oname);		if (r == 0 && strcmp(oname, rname) == 0) {			CAMLreturn(Val_some(caml_string_of_asn1_buf(&obj->val)));		}		obj = obj->next;	}	CAMLreturn(Val_none);}time_t time_to_time_t(mbedtls_x509_time* t) {	struct tm info;	info.tm_year = t->year - 1900;	info.tm_mon = t->mon - 1;	info.tm_mday = t->day;	info.tm_hour = t->hour;	info.tm_min = t->min;	info.tm_sec = t->sec;	return mktime(&info);}CAMLprim value hx_cert_get_notafter(value chain) {	CAMLparam1(chain);	mbedtls_x509_crt* cert = X509Crt_val(chain);	mbedtls_x509_time *t = &cert->valid_to;	time_t time = time_to_time_t(t);	CAMLreturn(caml_copy_double((double)time));}CAMLprim value hx_cert_get_notbefore(value chain) {	CAMLparam1(chain);	mbedtls_x509_crt* cert = X509Crt_val(chain);	mbedtls_x509_time *t = &cert->valid_from;	time_t time = time_to_time_t(t);	CAMLreturn(caml_copy_double((double)time));}// Config#define Config_val(v) (*((mbedtls_ssl_config**) Data_custom_val(v)))static void ml_mbedtls_ssl_config_finalize(value v) {	mbedtls_ssl_config* ssl_config = Config_val(v);	if (ssl_config != NULL) {		mbedtls_ssl_config_free(ssl_config);	}}static struct custom_operations ssl_config_ops = {	.identifier  = "ml_ssl_config",	.finalize    = ml_mbedtls_ssl_config_finalize,	.compare     = custom_compare_default,	.hash        = custom_hash_default,	.serialize   = custom_serialize_default,	.deserialize = custom_deserialize_default,};CAMLprim value ml_mbedtls_ssl_config_init(void) {	CAMLparam0();	CAMLlocal1(obj);	obj = caml_alloc_custom(&ssl_config_ops, sizeof(mbedtls_ssl_config*), 0, 1);	mbedtls_ssl_config* ssl_config = malloc(sizeof(mbedtls_ssl_config));	mbedtls_ssl_config_init(ssl_config);	Config_val(obj) = ssl_config;	CAMLreturn(obj);}CAMLprim value ml_mbedtls_ssl_conf_authmode(value conf, value authmode) {	CAMLparam2(conf, authmode);	mbedtls_ssl_conf_authmode(Config_val(conf), Int_val(authmode));	CAMLreturn(Val_unit);}CAMLprim value ml_mbedtls_ssl_conf_ca_chain(value conf, value ca_chain) {	CAMLparam2(conf, ca_chain);	mbedtls_ssl_conf_ca_chain(Config_val(conf), X509Crt_val(ca_chain), NULL);	CAMLreturn(Val_unit);}CAMLprim value ml_mbedtls_ssl_config_defaults(value conf, value endpoint, value transport, value preset) {	CAMLparam4(conf, endpoint, transport, preset);	CAMLreturn(Val_int(mbedtls_ssl_config_defaults(Config_val(conf), Int_val(endpoint), Int_val(transport), Int_val(preset))));}CAMLprim value ml_mbedtls_ssl_conf_rng(value conf, value p_rng) {	CAMLparam2(conf, p_rng);	mbedtls_ssl_conf_rng(Config_val(conf), mbedtls_ctr_drbg_random, PVoid_val(p_rng));	CAMLreturn(Val_unit);}// Pk#define PkContext_val(v) (*((mbedtls_pk_context**) Data_custom_val(v)))static void ml_mbedtls_pk_context_finalize(value v) {	mbedtls_pk_context* pk_context = PkContext_val(v);	if (pk_context != NULL) {		mbedtls_pk_free(pk_context);	}}static struct custom_operations pk_context_ops = {	.identifier  = "ml_pk_context",	.finalize    = ml_mbedtls_pk_context_finalize,	.compare     = custom_compare_default,	.hash        = custom_hash_default,	.serialize   = custom_serialize_default,	.deserialize = custom_deserialize_default,};CAMLprim value ml_mbedtls_pk_init(void) {	CAMLparam0();	CAMLlocal1(obj);	obj = caml_alloc_custom(&pk_context_ops, sizeof(mbedtls_pk_context*), 0, 1);	mbedtls_pk_context* pk_context = malloc(sizeof(mbedtls_pk_context));	mbedtls_pk_init(pk_context);	PkContext_val(obj) = pk_context;	CAMLreturn(obj);}CAMLprim value ml_mbedtls_pk_parse_key(value ctx, value key, value password) {	CAMLparam3(ctx, key, password);	const char* pwd = NULL;	size_t pwdlen = 0;	if (password != Val_none) {		pwd = String_val(Field(password, 0));		pwdlen = caml_string_length(Field(password, 0));	}	CAMLreturn(mbedtls_pk_parse_key(PkContext_val(ctx), String_val(key), caml_string_length(key) + 1, pwd, pwdlen));}CAMLprim value ml_mbedtls_pk_parse_keyfile(value ctx, value path, value password) {	CAMLparam3(ctx, path, password);	const char* pwd = NULL;	if (password != Val_none) {		pwd = String_val(Field(password, 0));	}	CAMLreturn(mbedtls_pk_parse_keyfile(PkContext_val(ctx), String_val(path), pwd));}CAMLprim value ml_mbedtls_pk_parse_public_key(value ctx, value key) {	CAMLparam2(ctx, key);	CAMLreturn(mbedtls_pk_parse_public_key(PkContext_val(ctx), String_val(key), caml_string_length(key) + 1));}CAMLprim value ml_mbedtls_pk_parse_public_keyfile(value ctx, value path) {	CAMLparam2(ctx, path);	CAMLreturn(mbedtls_pk_parse_public_keyfile(PkContext_val(ctx), String_val(path)));}// Ssl#define SslContext_val(v) (*((mbedtls_ssl_context**) Data_custom_val(v)))static void ml_mbedtls_ssl_context_finalize(value v) {	mbedtls_ssl_context* ssl_context = SslContext_val(v);	if (ssl_context != NULL) {		mbedtls_ssl_free(ssl_context);	}}static struct custom_operations ssl_context_ops = {	.identifier  = "ml_ssl_context",	.finalize    = ml_mbedtls_ssl_context_finalize,	.compare     = custom_compare_default,	.hash        = custom_hash_default,	.serialize   = custom_serialize_default,	.deserialize = custom_deserialize_default,};CAMLprim value ml_mbedtls_ssl_init(void) {	CAMLparam0();	CAMLlocal1(obj);	obj = caml_alloc_custom(&ssl_context_ops, sizeof(mbedtls_ssl_context*), 0, 1);	mbedtls_ssl_context* ssl_context = malloc(sizeof(mbedtls_ssl_context));	mbedtls_ssl_init(ssl_context);	SslContext_val(obj) = ssl_context;	CAMLreturn(obj);}CAMLprim value ml_mbedtls_ssl_get_peer_cert(value ssl) {	CAMLparam1(ssl);	CAMLlocal1(obj);	mbedtls_ssl_context* ssl_context = SslContext_val(ssl);	mbedtls_x509_crt* crt = (mbedtls_x509_crt*)mbedtls_ssl_get_peer_cert(ssl_context);	if (crt == NULL) {		CAMLreturn(Val_none);	}	obj = caml_alloc_custom(&x509_crt_ops, sizeof(mbedtls_x509_crt*), 0, 1);	X509Crt_val(obj) = crt;	CAMLreturn(Val_some(obj));}CAMLprim value ml_mbedtls_ssl_handshake(value ssl) {	CAMLparam1(ssl);	CAMLreturn(Val_int(mbedtls_ssl_handshake(SslContext_val(ssl))));}CAMLprim value ml_mbedtls_ssl_read(value ssl, value buf, value pos, value len) {	CAMLparam4(ssl, buf, pos, len);	CAMLreturn(Val_int(mbedtls_ssl_read(SslContext_val(ssl), String_val(buf) + Int_val(pos), Int_val(len))));}static int bio_write_cb(void* ctx, const unsigned char* buf, size_t len) {	CAMLparam0();	CAMLlocal3(r, s, vctx);	vctx = (value)ctx;	s = caml_alloc_string(len);	memcpy(String_val(s), buf, len);	r = caml_callback2(Field(vctx, 1), Field(vctx, 0), s);	CAMLreturn(Int_val(r));}static int bio_read_cb(void* ctx, unsigned char* buf, size_t len) {	CAMLparam0();	CAMLlocal3(r, s, vctx);	vctx = (value)ctx;	s = caml_alloc_string(len);	r = caml_callback2(Field(vctx, 2), Field(vctx, 0), s);	memcpy(buf, String_val(s), len);	CAMLreturn(Int_val(r));}CAMLprim value ml_mbedtls_ssl_set_bio(value ssl, value p_bio, value f_send, value f_recv) {	CAMLparam4(ssl, p_bio, f_send, f_recv);	CAMLlocal1(ctx);	ctx = caml_alloc(3, 0);	Store_field(ctx, 0, p_bio);	Store_field(ctx, 1, f_send);	Store_field(ctx, 2, f_recv);	mbedtls_ssl_set_bio(SslContext_val(ssl), (void*)ctx, bio_write_cb, bio_read_cb, NULL);	CAMLreturn(Val_unit);}CAMLprim value ml_mbedtls_ssl_set_hostname(value ssl, value hostname) {	CAMLparam2(ssl, hostname);	CAMLreturn(Val_int(mbedtls_ssl_set_hostname(SslContext_val(ssl), String_val(hostname))));}CAMLprim value ml_mbedtls_ssl_setup(value ssl, value conf) {	CAMLparam2(ssl, conf);	CAMLreturn(Val_int(mbedtls_ssl_setup(SslContext_val(ssl), Config_val(conf))));}CAMLprim value ml_mbedtls_ssl_write(value ssl, value buf, value pos, value len) {	CAMLparam4(ssl, buf, pos, len);	CAMLreturn(Val_int(mbedtls_ssl_write(SslContext_val(ssl), String_val(buf) + Int_val(pos), Int_val(len))));}// glueCAMLprim value hx_cert_load_defaults(value certificate) {	CAMLparam1(certificate);	int r = 1;	mbedtls_x509_crt *chain = X509Crt_val(certificate);	#ifdef _WIN32	HCERTSTORE store;	PCCERT_CONTEXT cert;	if (store = CertOpenSystemStore(0, "Root")) {		cert = NULL;		while (cert = CertEnumCertificatesInStore(store, cert)) {			r = mbedtls_x509_crt_parse_der(chain, (unsigned char *)cert->pbCertEncoded, cert->cbCertEncoded);			if (r != 0) {				CAMLreturn(Val_int(r));			}		}		CertCloseStore(store, 0);	}	#endif	#ifdef __APPLE__	CFMutableDictionaryRef search;	CFArrayRef result;	SecKeychainRef keychain;	SecCertificateRef item;	CFDataRef dat;	// Load keychain	if (SecKeychainOpen("/System/Library/Keychains/SystemRootCertificates.keychain", &keychain) == errSecSuccess) {		// Search for certificates		search = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);		CFDictionarySetValue(search, kSecClass, kSecClassCertificate);		CFDictionarySetValue(search, kSecMatchLimit, kSecMatchLimitAll);		CFDictionarySetValue(search, kSecReturnRef, kCFBooleanTrue);		CFDictionarySetValue(search, kSecMatchSearchList, CFArrayCreate(NULL, (const void **)&keychain, 1, NULL));		if (SecItemCopyMatching(search, (CFTypeRef *)&result) == errSecSuccess) {			CFIndex n = CFArrayGetCount(result);			for (CFIndex i = 0; i < n; i++) {				item = (SecCertificateRef)CFArrayGetValueAtIndex(result, i);				// Get certificate in DER format				dat = SecCertificateCopyData(item);				if (dat) {					r = mbedtls_x509_crt_parse_der(chain, (unsigned char *)CFDataGetBytePtr(dat), CFDataGetLength(dat));					CFRelease(dat);					if (r != 0) {						CAMLreturn(Val_int(r));					}				}			}		}		CFRelease(keychain);	}	#endif	CAMLreturn(Val_int(r));}static value build_fields(int num_fields, const char* names[], int values[]) {	CAMLparam0();	CAMLlocal2(ret, tuple);	ret = caml_alloc(num_fields, 0);	for (int i = 0; i < num_fields; ++i) {		tuple = caml_alloc_tuple(2);		Store_field(tuple, 0, caml_copy_string(names[i]));		Store_field(tuple, 1, Val_int(values[i]));		Store_field(ret, i, tuple);	}	CAMLreturn(ret);}CAMLprim value hx_get_ssl_authmode_flags(value unit) {	CAMLparam1(unit);	const char* names[] = {"SSL_VERIFY_NONE", "SSL_VERIFY_OPTIONAL", "SSL_VERIFY_REQUIRED"};	int values[] = {MBEDTLS_SSL_VERIFY_NONE, MBEDTLS_SSL_VERIFY_OPTIONAL, MBEDTLS_SSL_VERIFY_REQUIRED};	CAMLreturn(build_fields(sizeof(values) / sizeof(values[0]), names, values));}CAMLprim value hx_get_ssl_endpoint_flags(value unit) {	CAMLparam1(unit);	const char* names[] = {"SSL_IS_CLIENT", "SSL_IS_SERVER"};	int values[] = {MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_IS_SERVER};	CAMLreturn(build_fields(sizeof(values) / sizeof(values[0]), names, values));}CAMLprim value hx_get_ssl_preset_flags(value unit) {	CAMLparam1(unit);	const char* names[] = {"SSL_PRESET_DEFAULT", "SSL_PRESET_SUITEB"};	int values[] = {MBEDTLS_SSL_PRESET_DEFAULT, MBEDTLS_SSL_PRESET_SUITEB};	CAMLreturn(build_fields(sizeof(values) / sizeof(values[0]), names, values));}CAMLprim value hx_get_ssl_transport_flags(value unit) {	CAMLparam1(unit);	const char* names[] = {"SSL_TRANSPORT_STREAM", "SSL_TRANSPORT_DATAGRAM"};	int values[] = {MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_TRANSPORT_DATAGRAM};	CAMLreturn(build_fields(sizeof(values) / sizeof(values[0]), names, values));}
 |