git » sdk » commit c57bcf3

cpp snapshot for mbedtls3

author Stephen Paul Weber
2026-03-10 15:36:51 UTC
committer Stephen Paul Weber
2026-03-10 15:37:29 UTC
parent 48fdfdc897b8497b0499650fcbd8c6ddffa9833d

cpp snapshot for mbedtls3

Makefile +3 -2
cpp/alt/SSL-mbedtls3.cpp +854 -0

diff --git a/Makefile b/Makefile
index 8492928..e0c3e80 100644
--- a/Makefile
+++ b/Makefile
@@ -48,16 +48,17 @@ npm: npm/borogove-browser.js npm/borogove.js borogove/persistence/IDB.js borogov
 
 cpp/libborogove.dso:
 	haxe cpp.hxml
+	$(RM) cpp/libborogove.dso.hash
 
 cpp:
+	$(RM) -r cpp/obj
 	$(RM) cpp/src/__main__.cpp
 	$(RM) cpp/src/__files__.cpp
+	cp cpp/alt/SSL-mbedtls3.cpp cpp/src/hx/libs/ssl/SSL.cpp
 	cp "$(shell haxelib libpath hxcpp)"/include/*.h cpp/include/
 	cp -r "$(shell haxelib libpath hxcpp)"/include/hx cpp/include/
 	cp -r "$(shell haxelib libpath hxcpp)"/include/cpp cpp/include/
 	mkdir -p cpp/src/hx/libs/ssl
-	cp "$(shell haxelib libpath hxcpp)"/src/hx/libs/ssl/SSL.cpp cpp/src/hx/libs/ssl/
-	cp "$(shell haxelib libpath hxcpp)"/src/hx/libs/ssl/SSL.cpp cpp/src/hx/libs/ssl/
 	cp -r "$(shell haxelib libpath hxcpp)"/src/hx/libs/std cpp/src/hx/libs/
 	cp -r "$(shell haxelib libpath hxcpp)"/src/hx/libs/regexp cpp/src/hx/libs/
 	cp -r "$(shell haxelib libpath hxcpp)"/src/hx/libs/sqlite cpp/src/hx/libs/
diff --git a/cpp/alt/SSL-mbedtls3.cpp b/cpp/alt/SSL-mbedtls3.cpp
new file mode 100644
index 0000000..d6783e5
--- /dev/null
+++ b/cpp/alt/SSL-mbedtls3.cpp
@@ -0,0 +1,854 @@
+#include <string.h>
+
+#ifdef HX_WINDOWS
+#   include <winsock2.h>
+#   include <wincrypt.h>
+#else
+#   include <sys/socket.h>
+#   include <strings.h>
+#   include <errno.h>
+typedef int SOCKET;
+#endif
+
+#include <hxcpp.h>
+#include <hx/OS.h>
+
+#if defined(NEKO_MAC) && !defined(IPHONE) && !defined(APPLETV)
+#include <Security/Security.h>
+#endif
+
+typedef size_t socket_int;
+
+#define SOCKET_ERROR (-1)
+#define NRETRYS	20
+
+#include "mbedtls/error.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/md.h"
+#include "mbedtls/pk.h"
+#include "mbedtls/oid.h"
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/debug.h"
+
+#define val_ssl(o)	((sslctx*)o.mPtr)
+#define val_conf(o)	((sslconf*)o.mPtr)
+#define val_cert(o) ((sslcert*)o.mPtr)
+#define val_pkey(o) ((sslpkey*)o.mPtr)
+
+struct SocketWrapper : public hx::Object
+{
+   HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSocket };
+   SOCKET socket;
+};
+
+struct sslctx : public hx::Object
+{
+   HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSsl };
+
+	mbedtls_ssl_context *s;
+
+	void create()
+	{
+		s = (mbedtls_ssl_context *)malloc(sizeof(mbedtls_ssl_context));
+		mbedtls_ssl_init(s);
+		_hx_set_finalizer(this, finalize);
+	}
+
+	void destroy()
+	{
+		if( s )
+		{
+			mbedtls_ssl_free( s );
+			free(s);
+			s = 0;
+		}
+	}
+
+	static void finalize(Dynamic obj)
+	{
+		((sslctx *)(obj.mPtr))->destroy();
+	}
+
+	String toString() { return HX_CSTRING("sslctx"); }
+};
+
+struct sslconf : public hx::Object
+{
+   HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSslConf };
+
+	mbedtls_ssl_config *c;
+
+	void create()
+	{
+		c = (mbedtls_ssl_config *)malloc(sizeof(mbedtls_ssl_config));
+		mbedtls_ssl_config_init(c);
+		_hx_set_finalizer(this, finalize);
+	}
+
+	void destroy()
+	{
+		if( c )
+		{
+			mbedtls_ssl_config_free( c );
+			free(c);
+			c = 0;
+		}
+	}
+
+	static void finalize(Dynamic obj)
+	{
+		((sslconf *)(obj.mPtr))->destroy();
+	}
+
+	String toString() { return HX_CSTRING("sslconfig"); }
+};
+
+struct sslcert : public hx::Object
+{
+   HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSslCert };
+
+	mbedtls_x509_crt *c;
+	bool head;
+
+	void create(const mbedtls_x509_crt *inC)
+	{
+
+		if( inC ){
+			c = (mbedtls_x509_crt *)inC;
+			head = false;
+		}else{
+			c = (mbedtls_x509_crt *)malloc(sizeof(mbedtls_x509_crt));
+			mbedtls_x509_crt_init(c);
+			head = true;
+		}
+		_hx_set_finalizer(this, finalize);
+	}
+
+	void destroy()
+	{
+		if( c && head )
+		{
+			mbedtls_x509_crt_free( c );
+			free(c);
+			head = 0;
+		}
+		c = 0;
+	}
+
+	static void finalize(Dynamic obj)
+	{
+		((sslcert *)(obj.mPtr))->destroy();
+	}
+
+	String toString() { return HX_CSTRING("sslcert"); }
+};
+
+struct sslpkey : public hx::Object
+{
+   HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSslKey };
+
+	mbedtls_pk_context *k;
+
+	void create()
+	{
+		k = (mbedtls_pk_context *)malloc(sizeof(mbedtls_pk_context));
+		mbedtls_pk_init(k);
+		_hx_set_finalizer(this, finalize);
+	}
+
+	void destroy()
+	{
+		if( k )
+		{
+			mbedtls_pk_free(k);
+			free(k);
+			k = 0;
+		}
+	}
+
+	static void finalize(Dynamic obj)
+	{
+		((sslpkey *)(obj.mPtr))->destroy();
+	}
+
+	String toString() { return HX_CSTRING("sslpkey"); }
+};
+
+static mbedtls_entropy_context entropy;
+static mbedtls_ctr_drbg_context ctr_drbg;
+
+static bool is_ssl_blocking( int r ) {
+	return r == MBEDTLS_ERR_SSL_WANT_READ || r == MBEDTLS_ERR_SSL_WANT_WRITE;
+}
+
+static bool is_block_error() {
+	#ifdef NEKO_WINDOWS
+	int err = WSAGetLastError();
+	if( err == WSAEWOULDBLOCK || err == WSAEALREADY || err == WSAETIMEDOUT )
+	#else
+	if( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == EALREADY )
+	#endif
+		return true;
+	return false;
+}
+
+static void ssl_error( int ret ){
+	char buf[256];
+	mbedtls_strerror(ret, buf, sizeof(buf));
+	hx::Throw( String(buf) );
+}
+
+Dynamic _hx_ssl_new( Dynamic hconf ) {
+	int ret;
+	sslctx *ssl = new sslctx();
+	ssl->create();
+	sslconf *conf = val_conf(hconf);
+	if( ret = mbedtls_ssl_setup(ssl->s, conf->c) != 0 ){
+		ssl->destroy();
+		ssl_error(ret);
+	}
+	return ssl;
+}
+
+void _hx_ssl_close( Dynamic hssl ) {
+	sslctx *ssl = val_ssl(hssl);
+	ssl->destroy();
+}
+
+void _hx_ssl_debug_set (int i) {
+	mbedtls_debug_set_threshold(i);
+}
+
+void _hx_ssl_handshake( Dynamic hssl ) {
+	int r;
+	sslctx *ssl = val_ssl(hssl);
+	POSIX_LABEL(handshake_again);
+	r = mbedtls_ssl_handshake( ssl->s );
+	if ( is_ssl_blocking(r) ) {
+		HANDLE_EINTR(handshake_again);
+		hx::Throw(HX_CSTRING("Blocking"));
+	}else if( r == SOCKET_ERROR ) {
+		HANDLE_EINTR(handshake_again);
+		hx::Throw(HX_CSTRING("ssl network error"));
+	}else if( r != 0 )
+		ssl_error(r);
+}
+
+int net_read( void *fd, unsigned char *buf, size_t len ){
+	hx::EnterGCFreeZone();
+	int r = recv((SOCKET)(socket_int)fd, (char *)buf, len, 0);
+ 	if( r == SOCKET_ERROR && is_block_error() )
+ 		r = MBEDTLS_ERR_SSL_WANT_READ;
+	hx::ExitGCFreeZone();
+	return r;
+}
+
+int net_write( void *fd, const unsigned char *buf, size_t len ){
+	hx::EnterGCFreeZone();
+	int r = send((SOCKET)(socket_int)fd, (char *)buf, len, 0);
+	if( r == SOCKET_ERROR && is_block_error() )
+ 		r = MBEDTLS_ERR_SSL_WANT_WRITE;
+	hx::ExitGCFreeZone();
+	return r;
+}
+
+void _hx_ssl_set_socket( Dynamic hssl, Dynamic hsocket ) {
+	sslctx *ssl = val_ssl(hssl);
+	SocketWrapper *socket = (SocketWrapper *)hsocket.mPtr;
+	mbedtls_ssl_set_bio( ssl->s, (void *)(socket_int)socket->socket, net_write, net_read, NULL );
+}
+
+void _hx_ssl_set_hostname( Dynamic hssl, String hostname ){
+	int ret;
+	sslctx *ssl = val_ssl(hssl);
+	hx::strbuf buf;
+	if( ret = mbedtls_ssl_set_hostname(ssl->s, hostname.utf8_str(&buf)) != 0 )
+		ssl_error(ret);
+}
+
+Dynamic _hx_ssl_get_peer_certificate( Dynamic hssl ){
+	sslctx *ssl = val_ssl(hssl);
+	const mbedtls_x509_crt *crt = mbedtls_ssl_get_peer_cert(ssl->s);
+	if( crt == NULL )
+		return null();
+	sslcert *cert = new sslcert();
+	cert->create( crt );
+	return cert;
+}
+
+bool _hx_ssl_get_verify_result( Dynamic hssl ){
+	sslctx *ssl = val_ssl(hssl);
+	int r = mbedtls_ssl_get_verify_result( ssl->s );
+	if( r == 0 )
+		return true;
+	else if( r != -1 )
+		return false;
+	hx::Throw( HX_CSTRING("not available") );
+	return false;
+}
+
+void _hx_ssl_send_char( Dynamic hssl, int c ) {
+	if( c < 0 || c > 255 )
+		hx::Throw( HX_CSTRING("invalid char") );
+	sslctx *ssl = val_ssl(hssl);
+	const unsigned char cc = c;
+	mbedtls_ssl_write( ssl->s, &cc, 1 );
+}
+
+int _hx_ssl_send( Dynamic hssl, Array<unsigned char> buf, int p, int l ) {
+	sslctx *ssl = val_ssl(hssl);
+	int dlen = buf->length;
+	if( p < 0 || l < 0 || p > dlen || p + l > dlen )
+		hx::Throw( HX_CSTRING("ssl_send") );
+	POSIX_LABEL(send_again);
+	const unsigned char *base = (const unsigned char *)&buf[0];
+	dlen = mbedtls_ssl_write( ssl->s, base + p, l );
+	if ( is_ssl_blocking(dlen) ) {
+		HANDLE_EINTR(send_again);
+		hx::Throw(HX_CSTRING("Blocking"));
+	}else if( dlen == SOCKET_ERROR ) {
+		HANDLE_EINTR(send_again);
+		hx::Throw(HX_CSTRING("ssl network error"));
+	}
+	return dlen;
+}
+
+void _hx_ssl_write( Dynamic hssl, Array<unsigned char> buf ) {
+	sslctx *ssl = val_ssl(hssl);
+	int len = buf->length;
+	unsigned char *cdata = &buf[0];
+	while( len > 0 ) {
+		POSIX_LABEL( write_again );
+		int slen = mbedtls_ssl_write( ssl->s, cdata, len );
+		if ( is_ssl_blocking(slen) ) {
+			HANDLE_EINTR( write_again );
+			hx::Throw(HX_CSTRING("Blocking"));
+		}else if( slen == SOCKET_ERROR ) {
+			HANDLE_EINTR( write_again );
+			hx::Throw(HX_CSTRING("ssl network error"));
+		}
+		cdata += slen;
+		len -= slen;
+	}
+}
+
+int _hx_ssl_recv_char( Dynamic hssl ) {
+	sslctx *ssl = val_ssl(hssl);
+	unsigned char cc;
+	int r = mbedtls_ssl_read( ssl->s, &cc, 1 );
+	if( r <= 0 )
+		hx::Throw( HX_CSTRING("ssl_recv_char") );
+	return (int)cc;
+}
+
+int _hx_ssl_recv( Dynamic hssl, Array<unsigned char> buf, int p, int l ) {
+	sslctx *ssl = val_ssl(hssl);
+	int dlen = buf->length;
+	if( p < 0 || l < 0 || p > dlen || p + l > dlen )
+		hx::Throw( HX_CSTRING("ssl_recv") );
+
+	unsigned char *base = &buf[0];
+	POSIX_LABEL(recv_again);
+	dlen = mbedtls_ssl_read( ssl->s, base + p, l );
+	if ( is_ssl_blocking(dlen) ) {
+		HANDLE_EINTR(recv_again);
+		hx::Throw(HX_CSTRING("Blocking"));
+	}else if( dlen == SOCKET_ERROR ) {
+		HANDLE_EINTR(recv_again);
+		hx::Throw(HX_CSTRING("ssl network error"));
+	}
+	if( dlen < 0 ) {  
+                if( dlen == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY ) {
+                  mbedtls_ssl_close_notify( ssl->s );
+	  	  return 0;
+                }
+		hx::Throw( HX_CSTRING("ssl_recv") ); 
+	}
+	return dlen;
+}
+
+Array<unsigned char> _hx_ssl_read( Dynamic hssl ) {
+	sslctx *ssl = val_ssl(hssl);
+	Array<unsigned char> result = Array_obj<unsigned char>::__new();
+	unsigned char buf[256];
+
+	while( true ) {
+		POSIX_LABEL(read_again);
+		int len = mbedtls_ssl_read( ssl->s, buf, 256 );
+		if ( is_ssl_blocking(len) ) {
+			HANDLE_EINTR(read_again);
+			hx::Throw(HX_CSTRING("Blocking"));
+		}else if( len == SOCKET_ERROR ) {
+			HANDLE_EINTR(read_again);
+			hx::Throw(HX_CSTRING("ssl network error"));
+		}
+                if( len == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY ) {
+                  mbedtls_ssl_close_notify( ssl->s );
+	  	  len = 0;
+                }
+		if( len == 0 )
+			break;
+		result->memcpy(result->length, buf, len);
+	}
+	return result;
+}
+
+Dynamic _hx_ssl_conf_new( bool server ) {
+	int ret;
+	sslconf *conf = new sslconf();
+	conf->create();
+	if( ret = mbedtls_ssl_config_defaults( conf->c,
+		server ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT,
+		MBEDTLS_SSL_TRANSPORT_STREAM, 0 ) != 0 ){
+		conf->destroy();
+		ssl_error( ret );
+	}
+	mbedtls_ssl_conf_rng( conf->c, mbedtls_ctr_drbg_random, &ctr_drbg );
+	return conf;
+}
+
+void _hx_ssl_conf_close( Dynamic hconf ) {
+	sslconf *conf = val_conf(hconf);
+	conf->destroy();
+}
+
+void _hx_ssl_conf_set_ca( Dynamic hconf, Dynamic hcert ) {
+	sslconf *conf = val_conf(hconf);
+	if( hconf.mPtr ){
+		sslcert *cert = val_cert(hcert);
+		mbedtls_ssl_conf_ca_chain( conf->c, cert->c, NULL );
+	}else{
+		mbedtls_ssl_conf_ca_chain( conf->c, NULL, NULL );
+	}
+}
+
+void _hx_ssl_conf_set_verify( Dynamic hconf, int mode ) {
+	sslconf *conf = val_conf(hconf);
+	if( mode == 2 )
+		mbedtls_ssl_conf_authmode(conf->c, MBEDTLS_SSL_VERIFY_OPTIONAL);
+	else if( mode == 1 )
+		mbedtls_ssl_conf_authmode(conf->c, MBEDTLS_SSL_VERIFY_REQUIRED);
+	else
+		mbedtls_ssl_conf_authmode(conf->c, MBEDTLS_SSL_VERIFY_NONE);
+}
+
+void _hx_ssl_conf_set_cert( Dynamic hconf, Dynamic hcert, Dynamic hpkey ) {
+	int r;
+	sslconf *conf = val_conf(hconf);
+	sslcert *cert = val_cert(hcert);
+	sslpkey *pkey = val_pkey(hpkey);
+
+	if( r = mbedtls_ssl_conf_own_cert(conf->c, cert->c, pkey->k) != 0 )
+		ssl_error(r);
+}
+
+static int sni_callback( void *arg, mbedtls_ssl_context *ctx, const unsigned char *name, size_t len ){
+	if( name && arg ){
+		Dynamic cb = new Dynamic();
+		cb.mPtr = (hx::Object*)arg;
+		const char *n = (const char *)name;
+		Dynamic ret = cb->__run( String(n,strlen(n)) );
+		if( ret != null() ){
+			// TODO authmode and ca
+			Dynamic hcert = ret->__Field(HX_CSTRING("cert"), hx::paccDynamic);
+			Dynamic hpkey = ret->__Field(HX_CSTRING("key"), hx::paccDynamic);
+			sslcert *cert = val_cert(hcert);
+			sslpkey *pk = val_pkey(hpkey);
+
+			return mbedtls_ssl_set_hs_own_cert( ctx, cert->c, pk->k );
+		}
+	}
+	return -1;
+}
+
+void _hx_ssl_conf_set_servername_callback( Dynamic hconf, Dynamic cb ){
+	sslconf *conf = val_conf(hconf);
+	mbedtls_ssl_conf_sni( conf->c, sni_callback, (void *)cb.mPtr );
+}
+
+Dynamic _hx_ssl_cert_load_defaults(){
+#if defined(NEKO_WINDOWS)
+	HCERTSTORE store;
+	PCCERT_CONTEXT cert;
+	sslcert *chain = NULL;
+	if( store = CertOpenSystemStore(0, (LPCSTR)"Root") ){
+		cert = NULL;
+		while( cert = CertEnumCertificatesInStore(store, cert) ){
+			if( chain == NULL ){
+				chain = new sslcert();
+				chain->create( NULL );
+			}
+			mbedtls_x509_crt_parse_der( chain->c, (unsigned char *)cert->pbCertEncoded, cert->cbCertEncoded );
+		}
+		CertCloseStore(store, 0);
+	}
+	if( chain != NULL )
+		return chain;
+#elif defined(NEKO_MAC) && !defined(IPHONE) && !defined(APPLETV)
+	CFMutableDictionaryRef search;
+	CFArrayRef result;
+	SecKeychainRef keychain;
+	SecCertificateRef item;
+	CFDataRef dat;
+	sslcert *chain = NULL;
+
+	// Load keychain
+	if( SecKeychainOpen("/System/Library/Keychains/SystemRootCertificates.keychain",&keychain) != errSecSuccess )
+		return null();
+
+	// 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 ){
+				if( chain == NULL ){
+					chain = new sslcert();
+					chain->create( NULL );
+				}
+				mbedtls_x509_crt_parse_der( chain->c, (unsigned char *)CFDataGetBytePtr(dat), CFDataGetLength(dat) );
+				CFRelease( dat );
+			}
+		}
+	}
+	CFRelease(keychain);
+	if( chain != NULL )
+		return chain;
+#endif
+	return null();
+}
+
+Dynamic _hx_ssl_cert_load_file( String file ){
+	int r;
+	sslcert *cert = new sslcert();
+	cert->create( NULL );
+   hx::strbuf buf;
+	if( r = mbedtls_x509_crt_parse_file(cert->c, file.utf8_str(&buf)) != 0 ){
+		cert->destroy();
+		ssl_error(r);
+	}
+	return cert;
+}
+
+Dynamic _hx_ssl_cert_load_path( String path ){
+	int r;
+	sslcert *cert = new sslcert();
+	cert->create( NULL );
+   hx::strbuf buf;
+	if( r = mbedtls_x509_crt_parse_path(cert->c, path.utf8_str(&buf)) != 0 ){
+		cert->destroy();
+		ssl_error(r);
+	}
+	return cert;
+}
+
+static String asn1_buf_to_string( mbedtls_asn1_buf *dat ){
+	unsigned int i, c;
+	HX_CHAR *result = hx::NewString( dat->len );
+	for( i = 0; i < dat->len; i++ )  {
+        c = dat->p[i];
+        if( c < 32 || c == 127 || ( c > 128 && c < 160 ) )
+             result[i] = '?';
+        else
+			result[i] = c;
+    }
+	result[i] = '\0';
+	return String(result,dat->len);
+}
+
+String _hx_ssl_cert_get_subject( Dynamic hcert, String objname ){
+	mbedtls_x509_name *obj;
+	int r;
+	const char *oname;
+	sslcert *cert = val_cert(hcert);
+	obj = &cert->c->subject;
+	if( obj == NULL )
+		hx::Throw( HX_CSTRING("cert_get_subject") );
+   hx::strbuf buf;
+	while( obj != NULL ){
+		r = mbedtls_oid_get_attr_short_name( &obj->oid, &oname );
+		if( r == 0 && strcmp( oname, objname.utf8_str(&buf) ) == 0 )
+			return asn1_buf_to_string( &obj->val );
+		obj = obj->next;
+	}
+	return String();
+}
+
+String _hx_ssl_cert_get_issuer( Dynamic hcert, String objname ){
+	mbedtls_x509_name *obj;
+	int r;
+	const char *oname;
+	sslcert *cert = val_cert(hcert);
+	obj = &cert->c->issuer;
+	if( obj == NULL )
+		hx::Throw( HX_CSTRING("cert_get_issuer") );
+   hx::strbuf buf;
+	while( obj != NULL ){
+		r = mbedtls_oid_get_attr_short_name( &obj->oid, &oname );
+		if( r == 0 && strcmp( oname, objname.utf8_str(&buf) ) == 0 )
+			return asn1_buf_to_string( &obj->val );
+		obj = obj->next;
+	}
+	return String();
+}
+
+Array<String> _hx_ssl_cert_get_altnames( Dynamic hcert ){
+	sslcert *cert = val_cert(hcert);
+	mbedtls_asn1_sequence *cur;
+	Array<String> result(0,1);
+	if(mbedtls_x509_crt_has_ext_type(cert->c, MBEDTLS_X509_EXT_SUBJECT_ALT_NAME)){
+		cur = &cert->c->subject_alt_names;
+
+		while( cur != NULL ){
+			result.Add( asn1_buf_to_string(&cur->buf) );
+			cur = cur->next;
+		}
+	}
+	return result;
+}
+
+static Array<int> x509_time_to_array( mbedtls_x509_time *t ){
+	if( !t )
+		hx::Throw( HX_CSTRING("x509_time_to_array") );
+	Array<int> result(6,6);
+	result[0] = t->year;
+	result[1] = t->mon;
+	result[2] = t->day;
+	result[3] = t->hour;
+	result[4] = t->min;
+	result[5] = t->sec;
+	return result;
+}
+
+Array<int> _hx_ssl_cert_get_notbefore( Dynamic hcert ){
+	sslcert *cert = val_cert(hcert);
+	if( !cert->c )
+		hx::Throw( HX_CSTRING("cert_get_notbefore") );
+	return x509_time_to_array( &cert->c->valid_from );
+}
+
+Array<int> _hx_ssl_cert_get_notafter( Dynamic hcert ){
+	sslcert *cert = val_cert(hcert);
+	if( !cert->c )
+		hx::Throw( HX_CSTRING("cert_get_notafter") );
+	return x509_time_to_array( &cert->c->valid_to );
+}
+
+Dynamic _hx_ssl_cert_get_next( Dynamic hcert ){
+	sslcert *cert = val_cert(hcert);
+	mbedtls_x509_crt *crt = cert->c->next;
+	if( crt == NULL )
+		return null();
+	cert = new sslcert();
+	cert->create(crt);
+	return cert;
+}
+
+Dynamic _hx_ssl_cert_add_pem( Dynamic hcert, String data ){
+   #ifdef HX_SMART_STRINGS
+   if (data.isUTF16Encoded())
+		hx::Throw( HX_CSTRING("Invalid data encoding") );
+   #endif
+	sslcert *cert = val_cert(hcert);
+	int r;
+	bool isnew = 0;
+	if( !cert ){
+		cert = new sslcert();
+		cert->create( NULL );
+		isnew = 1;
+	}
+	unsigned char *b = (unsigned char *)malloc((data.length+1) * sizeof(unsigned char));
+	memcpy(b,data.raw_ptr(),data.length);
+	b[data.length] = '\0';
+	r = mbedtls_x509_crt_parse( cert->c, b, data.length+1 );
+	free(b);
+	if( r < 0 ){
+		if( isnew )
+			cert->destroy();
+		ssl_error(r);
+	}
+	return cert;
+}
+
+Dynamic _hx_ssl_cert_add_der( Dynamic hcert, Array<unsigned char> buf ){
+	sslcert *cert = val_cert(hcert);
+	int r;
+	bool isnew = 0;
+	if( !cert ){
+		cert = new sslcert();
+		cert->create( NULL );
+		isnew = 1;
+	}
+	if( (r = mbedtls_x509_crt_parse_der( cert->c, &buf[0], buf->length)) < 0 ){
+		if( isnew )
+			cert->destroy();
+		ssl_error(r);
+	}
+	return cert;
+}
+
+Dynamic _hx_ssl_key_from_der( Array<unsigned char> buf, bool pub ){
+	sslpkey *pk = new sslpkey();
+	pk->create();
+	int r;
+	if( pub )
+		r = mbedtls_pk_parse_public_key( pk->k, &buf[0], buf->length );
+	else
+		r = mbedtls_pk_parse_key( pk->k, &buf[0], buf->length, NULL, 0, mbedtls_ctr_drbg_random, &ctr_drbg);
+
+	if( r != 0 ){
+		pk->destroy();
+		ssl_error(r);
+	}
+	return pk;
+}
+
+Dynamic _hx_ssl_key_from_pem( String data, bool pub, String pass ){
+   #ifdef HX_SMART_STRINGS
+   if (data.isUTF16Encoded())
+		hx::Throw( HX_CSTRING("Invalid data encoding") );
+   #endif
+	sslpkey *pk = new sslpkey();
+	pk->create();
+	int r;
+	unsigned char *b = (unsigned char *)malloc((data.length+1) * sizeof(unsigned char));
+	memcpy(b,data.raw_ptr(),data.length);
+	b[data.length] = '\0';
+	if( pub ){
+		r = mbedtls_pk_parse_public_key( pk->k, b, data.length+1 );
+	}else if( pass == null() ){
+		r = mbedtls_pk_parse_key( pk->k, b, data.length+1, NULL, 0, mbedtls_ctr_drbg_random, &ctr_drbg);
+
+	}else{
+      Array<unsigned char> pbytes(0,0);
+      __hxcpp_bytes_of_string(pbytes,pass);
+		r = mbedtls_pk_parse_key( pk->k, b, data.length+1, (const unsigned char *)pbytes->GetBase(), pbytes->length, mbedtls_ctr_drbg_random, &ctr_drbg);
+
+	}
+	free(b);
+	if( r != 0 ){
+		pk->destroy();
+		ssl_error(r);
+	}
+	return pk;
+}
+
+Array<unsigned char> _hx_ssl_dgst_make( Array<unsigned char> buf, String alg ){
+   hx::strbuf ubuf;
+	const mbedtls_md_info_t *md = mbedtls_md_info_from_string(alg.utf8_str(&ubuf));
+	if( md == NULL )
+		hx::Throw( HX_CSTRING("Invalid hash algorithm") );
+
+	int size = mbedtls_md_get_size(md);
+	Array<unsigned char> out = Array_obj<int>::__new(size,size);
+	int r = -1;
+	if( r = mbedtls_md( md, &buf[0], buf->length, &out[0] ) != 0 )
+		ssl_error(r);
+
+	return out;
+}
+
+Array<unsigned char> _hx_ssl_dgst_sign( Array<unsigned char> buf, Dynamic hpkey, String alg ){
+	int r = -1;
+	size_t olen = 0;
+	unsigned char hash[32];
+	sslpkey *pk = val_pkey(hpkey);
+
+   hx::strbuf ubuf;
+	const mbedtls_md_info_t *md = mbedtls_md_info_from_string( alg.utf8_str(&ubuf) );
+	if( md == NULL )
+		hx::Throw( HX_CSTRING("Invalid hash algorithm") );
+
+	if( r = mbedtls_md( md, &buf[0], buf->length, hash ) != 0 )
+		ssl_error(r);
+
+	Array<unsigned char> result = Array_obj<unsigned char>::__new(MBEDTLS_MPI_MAX_SIZE,MBEDTLS_MPI_MAX_SIZE);
+	if( r = mbedtls_pk_sign( pk->k, mbedtls_md_get_type(md), hash, 0, &result[0], MBEDTLS_MPI_MAX_SIZE, &olen, mbedtls_ctr_drbg_random, &ctr_drbg ) != 0 )
+		ssl_error(r);
+
+	result[olen] = 0;
+	result->__SetSize(olen);
+	return result;
+}
+
+bool _hx_ssl_dgst_verify( Array<unsigned char> buf, Array<unsigned char> sign, Dynamic hpkey, String alg ){
+	const mbedtls_md_info_t *md;
+	int r = -1;
+	unsigned char hash[32];
+	sslpkey *pk = val_pkey(hpkey);
+
+   hx::strbuf ubuf;
+	md = mbedtls_md_info_from_string( alg.utf8_str(&ubuf) );
+	if( md == NULL )
+		hx::Throw( HX_CSTRING("Invalid hash algorithm") );
+
+	if( r = mbedtls_md( md, &buf[0], buf->length, hash ) != 0 )
+		ssl_error(r);
+
+	if( r = mbedtls_pk_verify( pk->k, mbedtls_md_get_type(md), hash, 0, &sign[0], sign->length ) != 0 )
+		return false;
+
+	return true;
+}
+
+#if (_MSC_VER || defined(WIN32))
+
+static void threading_mutex_init_alt( mbedtls_threading_mutex_t *mutex ){
+	if( mutex == NULL )
+		return;
+	InitializeCriticalSection( &mutex->cs );
+	mutex->is_valid = 1;
+}
+
+static void threading_mutex_free_alt( mbedtls_threading_mutex_t *mutex ){
+    if( mutex == NULL || !mutex->is_valid )
+        return;
+	DeleteCriticalSection( &mutex->cs );
+	mutex->is_valid = 0;
+}
+
+static int threading_mutex_lock_alt( mbedtls_threading_mutex_t *mutex ){
+    if( mutex == NULL || !mutex->is_valid )
+        return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA );
+
+	EnterCriticalSection( &mutex->cs );
+    return( 0 );
+}
+
+static int threading_mutex_unlock_alt( mbedtls_threading_mutex_t *mutex ){
+    if( mutex == NULL || !mutex->is_valid )
+        return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA );
+
+    LeaveCriticalSection( &mutex->cs );
+    return( 0 );
+}
+
+#endif
+
+static bool _hx_ssl_inited = false;
+void _hx_ssl_init() {
+    if (_hx_ssl_inited) return;
+    _hx_ssl_inited = true;
+
+#if (_MSC_VER || defined(WIN32))
+	mbedtls_threading_set_alt( threading_mutex_init_alt, threading_mutex_free_alt,
+                           threading_mutex_lock_alt, threading_mutex_unlock_alt );
+#endif
+
+	psa_crypto_init();
+
+	// Init RNG
+	mbedtls_entropy_init( &entropy );
+	mbedtls_ctr_drbg_init( &ctr_drbg );
+	mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0 );
+}