Ver código fonte

Add sys.ssl for neko and cpp

* Add sys.ssl for neko and cpp

* fix travis.yml

* [travis] sudo is required for mbedtls `make install`

* [cpp] Use native externs for SSL

* Fix sys.ssl.DigestAlgorithm

* Add private getter in sys.ssl.Certificate

* sys.ssl.Socket extends sys.net.Socket
Pascal Peridont 9 anos atrás
pai
commit
5f965678b7

+ 3 - 2
.travis.yml

@@ -23,7 +23,7 @@ env:
     - LUAROCKS=2.3.0
     - LUAROCKS=2.3.0
     - LUA=lua5.2
     - LUA=lua5.2
 
 
-sudo: false
+sudo: required
 addons:
 addons:
   ssh_known_hosts: haxe.org
   ssh_known_hosts: haxe.org
   apt:
   apt:
@@ -132,12 +132,13 @@ install:
   # Install haxe and neko dependencies
   # Install haxe and neko dependencies
   - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
   - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
     travis_retry brew update;
     travis_retry brew update;
-    travis_retry brew install ocaml camlp4 pcre;
+    travis_retry brew install ocaml camlp4 pcre mbedtls;
     fi
     fi
   # Install neko
   # Install neko
   - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then
   - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then
       travis_retry git clone https://github.com/HaxeFoundation/neko.git ~/neko;
       travis_retry git clone https://github.com/HaxeFoundation/neko.git ~/neko;
       cd ~/neko;
       cd ~/neko;
+      (cd libs/include/ssl/ && wget --no-check-certificate https://tls.mbed.org/download/mbedtls-2.2.1-apache.tgz && tar xzf mbedtls-2.2.1-apache.tgz && cd mbedtls-2.2.1 && sed -i "s/\/\/#define MBEDTLS_THREADING_PTHREAD/#define MBEDTLS_THREADING_PTHREAD/; s/\/\/#define MBEDTLS_THREADING_C/#define MBEDTLS_THREADING_C/; s/#define MBEDTLS_SSL_PROTO_SSL3/\/\/#define MBEDTLS_SSL_PROTO_SSL3/" include/mbedtls/config.h && SHARED=1 make lib && sudo make install);
       make os=${TRAVIS_OS_NAME} -s;
       make os=${TRAVIS_OS_NAME} -s;
       export PATH="$PATH:$HOME/neko/bin";
       export PATH="$PATH:$HOME/neko/bin";
       export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$HOME/neko/bin";
       export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$HOME/neko/bin";

+ 114 - 0
std/cpp/NativeSsl.hx

@@ -0,0 +1,114 @@
+package cpp;
+
+@:buildXml('<include name="${HXCPP}/src/hx/libs/ssl/Build.xml"/>')
+extern class NativeSsl
+{
+   @:extern @:native("_hx_ssl_new")
+   public static function ssl_new( conf : Dynamic ) : Dynamic { }
+
+   @:extern @:native("_hx_ssl_close")
+   public static function ssl_close( ctx : Dynamic ) : Void { }
+
+   @:extern @:native("_hx_ssl_handshake")
+   public static function ssl_handshake( ctx : Dynamic ) : Void { }
+
+   @:extern @:native("_hx_ssl_set_socket")
+   public static function ssl_set_socket( ctx : Dynamic, socket : Dynamic ) : Void { }
+
+   @:extern @:native("_hx_ssl_set_hostname")
+   public static function ssl_set_hostname( ctx : Dynamic, hostname : String ) : Void { }
+
+   @:extern @:native("_hx_ssl_get_peer_certificate")
+   public static function ssl_get_peer_certificate( ctx : Dynamic ) : Dynamic { }
+
+   @:extern @:native("_hx_ssl_get_verify_result")
+   public static function ssl_get_verify_result( ctx : Dynamic ) : Bool { }
+
+   @:extern @:native("_hx_ssl_send_char")
+   public static function ssl_send_char( ctx : Dynamic, char : Int ) : Void { }
+
+   @:extern @:native("_hx_ssl_send")
+   public static function ssl_send( ctx : Dynamic, buf : haxe.io.BytesData, p : Int, l : Int ) : Int { }
+
+   @:extern @:native("_hx_ssl_write")
+   public static function ssl_write( ctx : Dynamic, data : haxe.io.BytesData ) : Void { }
+
+   @:extern @:native("_hx_ssl_recv_char")
+   public static function ssl_recv_char( ctx : Dynamic ) : Int { }
+
+   @:extern @:native("_hx_ssl_recv")
+   public static function ssl_recv( ctx : Dynamic, buf : haxe.io.BytesData, p : Int, l : Int ) : Int { }
+
+   @:extern @:native("_hx_ssl_read")
+   public static function ssl_read( ctx : Dynamic ) : haxe.io.BytesData { }
+
+   @:extern @:native("_hx_ssl_conf_new")
+   public static function conf_new( server : Bool ) : Dynamic { }
+
+   @:extern @:native("_hx_ssl_conf_close")
+   public static function conf_close( conf : Dynamic ) : Void { }
+
+   @:extern @:native("_hx_ssl_conf_set_ca")
+   public static function conf_set_ca( conf : Dynamic, cert : Dynamic ) : Void { }
+
+   @:extern @:native("_hx_ssl_conf_set_verify")
+   public static function conf_set_verify( conf : Dynamic, mode : Int ) : Void { }
+
+   @:extern @:native("_hx_ssl_conf_set_cert")
+   public static function conf_set_cert( conf : Dynamic, cert : Dynamic, pkey : Dynamic ) : Void { }
+
+   @:extern @:native("_hx_ssl_conf_set_servername_callback")
+   public static function conf_set_servername_callback( conf : Dynamic, cb : Dynamic ) : Void { }
+
+   @:extern @:native("_hx_ssl_cert_load_defaults")
+   public static function cert_load_defaults() : Dynamic { }
+
+   @:extern @:native("_hx_ssl_cert_load_file")
+   public static function cert_load_file( file : String ) : Dynamic { }
+
+   @:extern @:native("_hx_ssl_cert_load_path")
+   public static function cert_load_path( path : String ) : Dynamic { }
+
+   @:extern @:native("_hx_ssl_cert_get_subject")
+   public static function cert_get_subject( cert : Dynamic, field : String ) : String { }
+
+   @:extern @:native("_hx_ssl_cert_get_issuer")
+   public static function cert_get_issuer( cert : Dynamic, field : String ) : String { }
+
+   @:extern @:native("_hx_ssl_cert_get_altnames")
+   public static function cert_get_altnames( cert : Dynamic ) : Array<String> { }
+
+   @:extern @:native("_hx_ssl_cert_get_notbefore")
+   public static function cert_get_notbefore( cert : Dynamic ) : Array<Int> { }
+
+   @:extern @:native("_hx_ssl_cert_get_notafter")
+   public static function cert_get_notafter( cert : Dynamic ) : Array<Int> { }
+
+   @:extern @:native("_hx_ssl_cert_get_next")
+   public static function cert_get_next( cert : Dynamic ) : Dynamic { }
+
+   @:extern @:native("_hx_ssl_cert_add_pem")
+   public static function cert_add_pem( cert : Dynamic, data : String ) : Dynamic { }
+
+   @:extern @:native("_hx_ssl_cert_add_der")
+   public static function cert_add_der( cert : Dynamic, data : haxe.io.BytesData ) : Dynamic { }
+
+   @:extern @:native("_hx_ssl_key_from_der")
+   public static function key_from_der( data : haxe.io.BytesData, pub : Bool ) : Dynamic { }
+
+   @:extern @:native("_hx_ssl_key_from_pem")
+   public static function key_from_pem( data : String, pub : Bool, pass : String ) : Dynamic { }
+
+   @:extern @:native("_hx_ssl_dgst_make")
+   public static function dgst_make( data : haxe.io.BytesData, alg : String ) : haxe.io.BytesData { }
+
+   @:extern @:native("_hx_ssl_dgst_sign")
+   public static function dgst_sign( data : haxe.io.BytesData, key : Dynamic, alg : String ) : haxe.io.BytesData { }
+
+   @:extern @:native("_hx_ssl_dgst_verify")
+   public static function dgst_verify( data : haxe.io.BytesData, sign : haxe.io.BytesData, key : Dynamic, alg : String ) : Bool { }
+
+   @:extern @:native("_hx_ssl_init")
+   public static function init() : Void { }
+
+}

+ 5 - 1
std/cpp/_std/sys/net/Socket.hx

@@ -120,7 +120,11 @@ class Socket {
 	public var custom : Dynamic;
 	public var custom : Dynamic;
 
 
 	public function new() : Void {
 	public function new() : Void {
-		__s = NativeSocket.socket_new(false);
+		init();
+	}
+
+	private function init() : Void {
+		if( __s != null )__s = NativeSocket.socket_new(false);
 		input = new SocketInput(__s);
 		input = new SocketInput(__s);
 		output = new SocketOutput(__s);
 		output = new SocketOutput(__s);
 	}
 	}

+ 2 - 2
std/cpp/_std/sys/net/UdpSocket.hx

@@ -26,9 +26,9 @@ import cpp.NativeSocket;
 @:coreApi
 @:coreApi
 class UdpSocket extends Socket {
 class UdpSocket extends Socket {
 
 
-	public function new() : Void {
+	private override function init() : Void {
 		__s = NativeSocket.socket_new(true);
 		__s = NativeSocket.socket_new(true);
-		super();
+		super.init();
 	}
 	}
 
 
 	public function sendTo( buf : haxe.io.Bytes, pos : Int, len : Int, addr : Address ) : Int {
 	public function sendTo( buf : haxe.io.Bytes, pos : Int, len : Int, addr : Address ) : Int {

+ 115 - 0
std/cpp/_std/sys/ssl/Certificate.hx

@@ -0,0 +1,115 @@
+package sys.ssl;
+import cpp.NativeSsl;
+
+@:coreApi
+class Certificate {
+	
+	var __h : Null<Certificate>;
+	var __x : Dynamic;
+
+	@:allow(sys.ssl.Socket)
+	function new( x : Dynamic, ?h: Null<Certificate> ){
+		__x = x;
+		__h = h;
+	}
+
+	public static function loadFile( file : String ) : Certificate {
+		return new Certificate( NativeSsl.cert_load_file( file ) );
+	}
+	
+	public static function loadPath( path : String ) : Certificate {
+		return new Certificate( NativeSsl.cert_load_path( path ) );
+	}
+
+	public static function fromString( str : String ) : Certificate {
+		return new Certificate( NativeSsl.cert_add_pem(null, str) );
+	}
+
+	public static function loadDefaults() : Certificate {
+		var x = NativeSsl.cert_load_defaults();
+		if ( x != null )
+			return new Certificate( x );
+		
+		var defPaths = null;
+		switch( Sys.systemName() ){
+			case "Linux":
+				defPaths = [
+					"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
+					"/etc/pki/tls/certs/ca-bundle.crt",   // Fedora/RHEL
+					"/etc/ssl/ca-bundle.pem",             // OpenSUSE
+					"/etc/pki/tls/cacert.pem",            // OpenELEC
+					"/etc/ssl/certs",                     // SLES10/SLES11
+					"/system/etc/security/cacerts"        // Android
+				];
+			case "BSD":
+				defPaths = [
+					"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly
+					"/etc/ssl/cert.pem",                      // OpenBSD
+					"/etc/openssl/certs/ca-certificates.crt", // NetBSD	
+				];
+			case "Android":
+				defPaths = ["/system/etc/security/cacerts"];
+			default:
+		}
+		if( defPaths != null ){
+			for ( path in defPaths ){
+				if ( sys.FileSystem.exists(path) ){
+					if( sys.FileSystem.isDirectory(path) )
+						return loadPath(path);
+					else
+						return loadFile(path);
+				}
+			}
+		}
+		return null;
+	}
+
+	public var commonName(get,null) : Null<String>;
+	public var altNames(get, null) : Array<String>;
+	public var notBefore(get,null) : Date;
+	public var notAfter(get,null) : Date;
+
+	function get_commonName() : Null<String> {
+		return subject("CN");
+	}
+
+	function get_altNames() : Array<String> {
+		return NativeSsl.cert_get_altnames(__x);
+	}
+	
+	public function subject( field : String ) : Null<String> {
+		return NativeSsl.cert_get_subject(__x, field);
+	}
+	
+	public function issuer( field : String ) : Null<String> {
+		return NativeSsl.cert_get_issuer(__x, field);
+	}
+
+	function get_notBefore() : Date {
+		var a = NativeSsl.cert_get_notbefore( __x );
+		return new Date( a[0], a[1] - 1, a[2], a[3], a[4], a[5] );
+	}
+
+	function get_notAfter() : Date {
+		var a = NativeSsl.cert_get_notafter( __x );
+		return new Date( a[0], a[1] - 1, a[2], a[3], a[4], a[5] );
+	}
+	
+	public function next() : Null<Certificate> {
+		var n = NativeSsl.cert_get_next(__x);
+		return n == null ? null : new Certificate( n, __h==null ? this : __h );
+	}
+
+	public function add( pem : String ) : Void {
+		NativeSsl.cert_add_pem(__x,pem);
+	}
+
+	public function addDER( der : haxe.io.Bytes ) : Void {
+		NativeSsl.cert_add_der(__x,der.getData());
+	}
+
+	static function __init__() : Void {
+		NativeSsl.init();
+	}
+
+}

+ 19 - 0
std/cpp/_std/sys/ssl/Digest.hx

@@ -0,0 +1,19 @@
+package sys.ssl;
+import cpp.NativeSsl;
+
+@:coreApi
+class Digest {
+
+	public static function make( data : haxe.io.Bytes, alg : DigestAlgorithm ) : haxe.io.Bytes {
+		return haxe.io.Bytes.ofData( NativeSsl.dgst_make( data.getData(), alg ) );
+	}
+	
+	public static function sign( data : haxe.io.Bytes, privKey : Key, alg : DigestAlgorithm ) : haxe.io.Bytes {
+		return haxe.io.Bytes.ofData( NativeSsl.dgst_sign( data.getData(), @:privateAccess privKey.__k, alg ) );
+	}
+	
+	public static function verify( data : haxe.io.Bytes, signature : haxe.io.Bytes, pubKey : Key, alg : DigestAlgorithm ) : Bool{
+		return NativeSsl.dgst_verify( data.getData(), signature.getData(), @:privateAccess pubKey.__k, alg );
+	}
+
+}

+ 36 - 0
std/cpp/_std/sys/ssl/Key.hx

@@ -0,0 +1,36 @@
+package sys.ssl;
+import cpp.NativeSsl;
+
+private typedef PKEY = Dynamic;
+
+@:coreApi
+class Key {
+	
+	private var __k : PKEY;
+
+	private function new( k : PKEY ){
+		__k = k;
+	}
+	
+	public static function loadFile( file : String, ?isPublic : Bool, ?pass : String ) : Key {
+		var data = sys.io.File.getBytes( file );
+		var str = cpp.Lib.stringReference(data);
+		if( str.indexOf("-----BEGIN ") >= 0 )
+			return readPEM( str, isPublic==true, pass );
+		else
+			return readDER( data, isPublic==true );
+	}
+	
+	public static function readPEM( data : String, isPublic : Bool, ?pass : String ) : Key {
+		return new Key( NativeSsl.key_from_pem( data, isPublic, pass ) );
+	}
+
+	public static function readDER( data : haxe.io.Bytes, isPublic : Bool ) : Key {
+		return new Key( NativeSsl.key_from_der( data.getData(), isPublic ) );
+	}
+
+	static function __init__() : Void {
+		NativeSsl.init();
+	}
+
+}

+ 269 - 0
std/cpp/_std/sys/ssl/Socket.hx

@@ -0,0 +1,269 @@
+package sys.ssl;
+import cpp.NativeSocket;
+import cpp.NativeSsl;
+
+private typedef SocketHandle = Dynamic;
+private typedef CONF = Dynamic;
+private typedef SSL = Dynamic;
+
+private class SocketInput extends haxe.io.Input {
+	@:allow(sys.ssl.Socket) private var __s : Socket;
+
+	public function new( s : Socket ) {
+		this.__s = s;
+	}
+
+	public override function readByte() {
+		return try {
+			__s.handshake();
+			NativeSsl.ssl_recv_char( @:privateAccess __s.ssl );
+		} catch( e : Dynamic ) {
+			if( e == "Blocking" )
+				throw haxe.io.Error.Blocked;
+			else if( __s == null )
+				throw haxe.io.Error.Custom(e);
+			else
+				throw new haxe.io.Eof();
+		}
+	}
+
+	public override function readBytes( buf : haxe.io.Bytes, pos : Int, len : Int ) : Int {
+		var r : Int;
+		if( __s == null )
+			throw "Invalid handle";
+		try {
+			__s.handshake();
+			r = NativeSsl.ssl_recv( @:privateAccess __s.ssl, buf.getData(), pos, len );
+		} catch( e : Dynamic ) {
+			if( e == "Blocking" )
+				throw haxe.io.Error.Blocked;
+			else
+				throw haxe.io.Error.Custom(e);
+		}
+		if( r == 0 )
+			throw new haxe.io.Eof();
+		return r;
+	}
+
+	public override function close() {
+		super.close();
+		if( __s != null ) __s.close();
+	}
+
+}
+
+private class SocketOutput extends haxe.io.Output {
+	@:allow(sys.ssl.Socket) private var __s : Socket;
+
+	public function new( s : Socket ) {
+		this.__s = s;
+	}
+
+	public override function writeByte( c : Int ) {
+		if( __s == null )
+			throw "Invalid handle";
+		try {
+			__s.handshake();
+			NativeSsl.ssl_send_char( @:privateAccess __s.ssl, c );
+		} catch( e : Dynamic ) {
+			if( e == "Blocking" )
+				throw haxe.io.Error.Blocked;
+			else
+				throw haxe.io.Error.Custom(e);
+		}
+	}
+
+	public override function writeBytes( buf : haxe.io.Bytes, pos : Int, len : Int) : Int {
+		return try {
+			__s.handshake();
+			NativeSsl.ssl_send( @:privateAccess __s.ssl, buf.getData(), pos, len );
+		} catch( e : Dynamic ) {
+			if( e == "Blocking" )
+				throw haxe.io.Error.Blocked;
+			else
+				throw haxe.io.Error.Custom(e);
+		}
+	}
+
+	public override function close() {
+		super.close();
+		if( __s != null ) __s.close();
+	}
+
+}
+
+@:coreApi
+class Socket extends sys.net.Socket {
+	
+	public static var DEFAULT_VERIFY_CERT : Null<Bool> = true;
+
+	public static var DEFAULT_CA : Null<Certificate>;
+	
+	private var conf : CONF;
+	private var ssl : SSL;
+	
+	public var verifyCert : Null<Bool>;
+	private var caCert : Null<Certificate>;
+	private var hostname : String;
+
+	private var ownCert : Null<Certificate>;
+	private var ownKey : Null<Key>;
+	private var altSNIContexts : Null<Array<{match: String->Bool, key: Key, cert: Certificate}>>;
+	private var sniCallback : Dynamic;
+	private var handshakeDone : Bool;
+
+	private override function init() : Void {
+		__s = NativeSocket.socket_new( false );
+		input = new SocketInput( this );
+		output = new SocketOutput( this );
+		if( DEFAULT_VERIFY_CERT && DEFAULT_CA == null ){
+			try {
+				DEFAULT_CA = Certificate.loadDefaults();
+			}catch( e : Dynamic ){}
+		}	
+		caCert = DEFAULT_CA;
+		verifyCert = DEFAULT_VERIFY_CERT;
+	}
+
+	public override function connect(host : sys.net.Host, port : Int) : Void {
+		try {
+			conf = buildSSLConfig( false );
+			ssl = NativeSsl.ssl_new( conf );
+			handshakeDone = false;
+			NativeSsl.ssl_set_socket( ssl, __s );
+			if( hostname == null )
+				hostname = host.host;
+			if( hostname != null )
+				NativeSsl.ssl_set_hostname( ssl, hostname );
+			NativeSocket.socket_connect( __s, host.ip, port );
+			handshake();
+		} catch( s : String ) {
+			if( s == "Invalid socket handle" )
+				throw "Failed to connect on "+host.host+":"+port;
+			else
+				cpp.Lib.rethrow(s);
+		} catch( e : Dynamic ) {
+			cpp.Lib.rethrow(e);
+		}
+	}
+
+	public function handshake() : Void {
+		if( !handshakeDone ){
+			try {
+				NativeSsl.ssl_handshake( ssl );
+				handshakeDone = true;
+			} catch( e : Dynamic ) {
+				if( e == "Blocking" )
+					throw haxe.io.Error.Blocked;
+				else
+					cpp.Lib.rethrow( e );
+			}
+		}
+	}
+
+	public function setCA( cert : Certificate ) : Void {
+		caCert = cert;
+	}
+
+	public function setHostname( name : String ) : Void {
+		hostname = name;
+	}
+
+	public function setCertificate( cert : Certificate, key : Key ) : Void {
+		ownCert = cert;
+		ownKey = key;
+	}
+
+	public override function read() : String {
+		handshake();
+		var b = NativeSsl.ssl_read( ssl );
+		if( b == null )
+			return "";
+		return haxe.io.Bytes.ofData(b).toString();
+	}
+
+	public override function write( content : String ) : Void {
+		handshake();
+		NativeSsl.ssl_write( ssl, haxe.io.Bytes.ofString(content).getData() );
+	}
+
+	public override function close() : Void {
+		if( ssl != null ) NativeSsl.ssl_close( ssl );
+		if( conf != null ) NativeSsl.conf_close( conf );
+		if( altSNIContexts != null )
+			sniCallback = null;
+		NativeSocket.socket_close( __s );
+		var input : SocketInput = cast input;
+		var output : SocketOutput = cast output;
+		@:privateAccess input.__s = output.__s = null;
+		input.close();
+		output.close();
+	}
+
+	public function addSNICertificate( cbServernameMatch : String->Bool, cert : Certificate, key : Key ) : Void {
+		if( altSNIContexts == null )
+			altSNIContexts = [];
+		altSNIContexts.push( {match: cbServernameMatch, cert: cert, key: key} );
+	}
+
+	public override function bind( host : sys.net.Host, port : Int ) : Void {
+		conf = buildSSLConfig( true );
+
+		NativeSocket.socket_bind( __s, host.ip, port );
+	}
+
+	public override function accept() : Socket {
+		var c = NativeSocket.socket_accept( __s );
+		var ssl = NativeSsl.ssl_new( conf );
+		NativeSsl.ssl_set_socket( ssl, c );
+
+		var s = Type.createEmptyInstance( sys.ssl.Socket );
+		s.__s = c;
+		s.ssl = ssl;
+		s.input = new SocketInput(s);
+		s.output = new SocketOutput(s);
+		s.handshakeDone = false;
+
+		return s;
+	}
+
+	public function peerCertificate() : sys.ssl.Certificate {
+		var x = NativeSsl.ssl_get_peer_certificate( ssl );
+		return x==null ? null : new sys.ssl.Certificate( x );
+	}
+
+	private function buildSSLConfig( server : Bool ) : CONF {
+		var conf : CONF = NativeSsl.conf_new( server );
+
+		if( ownCert != null && ownKey != null )
+			NativeSsl.conf_set_cert( conf, @:privateAccess ownCert.__x, @:privateAccess ownKey.__k );
+
+		if ( altSNIContexts != null ) {
+			sniCallback = function(servername) {
+				trace("SNI haxe function called with name="+servername);
+				var servername = new String(cast servername);
+				for( c in altSNIContexts ){
+					if( c.match(servername) )
+						return @:privateAccess {key: c.key.__k, cert: c.cert.__x};
+				}
+				if( ownKey != null && ownCert != null )
+					return @:privateAccess { key: ownKey.__k, cert: ownCert.__x };
+				return null;
+			}
+			NativeSsl.conf_set_servername_callback( conf, sniCallback );
+		}
+
+		if ( caCert != null ) 
+			NativeSsl.conf_set_ca( conf, caCert == null ? null : @:privateAccess caCert.__x  );
+		if( verifyCert == null )
+			NativeSsl.conf_set_verify( conf, 2 );
+		else
+			NativeSsl.conf_set_verify( conf, verifyCert ? 1 : 0 );
+		
+		return conf;
+	}
+
+	static function __init__() : Void {
+		NativeSsl.init();
+	}
+}

+ 3 - 17
std/haxe/Http.hx

@@ -26,16 +26,6 @@ package haxe;
 import sys.net.Host;
 import sys.net.Host;
 import sys.net.Socket;
 import sys.net.Socket;
 
 
-private typedef AbstractSocket = {
-	var input(default,null) : haxe.io.Input;
-	var output(default,null) : haxe.io.Output;
-	function connect( host : Host, port : Int ) : Void;
-	function setTimeout( t : Float ) : Void;
-	function write( str : String ) : Void;
-	function close() : Void;
-	function shutdown( read : Bool, write : Bool ) : Void;
-}
-
 #end
 #end
 
 
 /**
 /**
@@ -371,7 +361,7 @@ class Http {
 		this.file = { param : argname, filename : filename, io : file, size : size, mimeType : mimeType };
 		this.file = { param : argname, filename : filename, io : file, size : size, mimeType : mimeType };
 	}
 	}
 
 
-	public function customRequest( post : Bool, api : haxe.io.Output, ?sock : AbstractSocket, ?method : String  ) {
+	public function customRequest( post : Bool, api : haxe.io.Output, ?sock : sys.net.Socket, ?method : String  ) {
 		this.responseData = null;
 		this.responseData = null;
 		var url_regexp = ~/^(https?:\/\/)?([a-zA-Z\.0-9_-]+)(:[0-9]+)?(.*)$/;
 		var url_regexp = ~/^(https?:\/\/)?([a-zA-Z\.0-9_-]+)(:[0-9]+)?(.*)$/;
 		if( !url_regexp.match(url) ) {
 		if( !url_regexp.match(url) ) {
@@ -385,12 +375,8 @@ class Http {
 				sock = new php.net.SslSocket();
 				sock = new php.net.SslSocket();
 				#elseif java
 				#elseif java
 				sock = new java.net.SslSocket();
 				sock = new java.net.SslSocket();
-				#elseif hxssl
-				#if neko
-				sock = new neko.tls.Socket();
-				#else
+				#elseif (hxssl || cpp || (neko && !(macro || interp)))
 				sock = new sys.ssl.Socket();
 				sock = new sys.ssl.Socket();
-				#end
 				#else
 				#else
 				throw "Https is only supported with -lib hxssl";
 				throw "Https is only supported with -lib hxssl";
 				#end
 				#end
@@ -535,7 +521,7 @@ class Http {
 		}
 		}
 	}
 	}
 
 
-	function readHttpResponse( api : haxe.io.Output, sock : AbstractSocket ) {
+	function readHttpResponse( api : haxe.io.Output, sock : sys.net.Socket ) {
 		// READ the HTTP header (until \r\n\r\n)
 		// READ the HTTP header (until \r\n\r\n)
 		var b = new haxe.io.BytesBuffer();
 		var b = new haxe.io.BytesBuffer();
 		var k = 4;
 		var k = 4;

+ 4 - 0
std/neko/_std/sys/net/Socket.hx

@@ -124,6 +124,10 @@ class Socket {
 	public var custom : Dynamic;
 	public var custom : Dynamic;
 
 
 	public function new() : Void {
 	public function new() : Void {
+		init();
+	}
+
+	private function init() : Void {
 		if( __s == null ) __s = socket_new(false);
 		if( __s == null ) __s = socket_new(false);
 		input = new SocketInput(__s);
 		input = new SocketInput(__s);
 		output = new SocketOutput(__s);
 		output = new SocketOutput(__s);

+ 2 - 2
std/neko/_std/sys/net/UdpSocket.hx

@@ -25,9 +25,9 @@ import haxe.io.Error;
 @:coreApi
 @:coreApi
 class UdpSocket extends Socket {
 class UdpSocket extends Socket {
 
 
-	public function new() : Void {
+	private override function init() : Void {
 		__s = Socket.socket_new(true);
 		__s = Socket.socket_new(true);
-		super();
+		super.init();
 	}
 	}
 
 
 	public function sendTo( buf : haxe.io.Bytes, pos : Int, len : Int, addr : Address ) : Int {
 	public function sendTo( buf : haxe.io.Bytes, pos : Int, len : Int, addr : Address ) : Int {

+ 131 - 0
std/neko/_std/sys/ssl/Certificate.hx

@@ -0,0 +1,131 @@
+package sys.ssl;
+
+@:coreApi
+class Certificate {
+	
+	var __h : Null<Certificate>;
+	var __x : Dynamic;
+
+	@:allow(sys.ssl.Socket)
+	function new( x : Dynamic, ?h: Null<Certificate> ){
+		__x = x;
+		__h = h;
+	}
+
+	public static function loadFile( file : String ) : Certificate {
+		return new Certificate( cert_load_file( untyped file.__s ) );
+	}
+	
+	public static function loadPath( path : String ) : Certificate {
+		return new Certificate( cert_load_path( untyped path.__s ) );
+	}
+
+	public static function fromString( str : String ) : Certificate {
+		return new Certificate( cert_add_pem(null, untyped str.__s) );
+	}
+	
+	public static function loadDefaults() : Certificate {
+		var x = cert_load_defaults();
+		if ( x != null )
+			return new Certificate( x );
+		
+		var defPaths = null;
+		switch( Sys.systemName() ){
+			case "Linux":
+				defPaths = [
+					"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
+					"/etc/pki/tls/certs/ca-bundle.crt",   // Fedora/RHEL
+					"/etc/ssl/ca-bundle.pem",             // OpenSUSE
+					"/etc/pki/tls/cacert.pem",            // OpenELEC
+					"/etc/ssl/certs",                     // SLES10/SLES11
+					"/system/etc/security/cacerts"        // Android
+				];
+			case "BSD":
+				defPaths = [
+					"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly
+					"/etc/ssl/cert.pem",                      // OpenBSD
+					"/etc/openssl/certs/ca-certificates.crt", // NetBSD	
+				];
+			case "Android":
+				defPaths = ["/system/etc/security/cacerts"];
+			default:
+		}
+		if( defPaths != null ){
+			for( path in defPaths ){
+				if( sys.FileSystem.exists(path) ){
+					if( sys.FileSystem.isDirectory(path) )
+						return loadPath(path);
+					else
+						return loadFile(path);
+				}
+			}
+		}
+		return null;
+	}
+
+	public var commonName(get,null) : Null<String>;
+	public var altNames(get, null) : Array<String>;
+	public var notBefore(get,null) : Date;
+	public var notAfter(get,null) : Date;
+
+	function get_commonName() : Null<String> {
+		return subject("CN");
+	}
+
+	function get_altNames() : Array<String> {
+		var l : Dynamic = cert_get_altnames(__x);
+		var a = new Array<String>();
+		while( l != null ){
+			a.push(new String(l[0]));
+			l = l[1];
+		}
+		return a;
+	}
+	
+	public function subject( field : String ) : Null<String> {
+		var s = cert_get_subject(__x, untyped field.__s);
+		return s==null ? null : new String( cast s );
+	}
+	
+	public function issuer( field : String ) : Null<String> {
+		var s = cert_get_issuer(__x, untyped field.__s);
+		return s==null ? null : new String( cast s );
+	}
+
+	function get_notBefore() : Date {
+		var a = cert_get_notbefore( __x );
+		return new Date( a[0], a[1] - 1, a[2], a[3], a[4], a[5] );
+	}
+
+	function get_notAfter() : Date {
+		var a = cert_get_notafter( __x );
+		return new Date( a[0], a[1] - 1, a[2], a[3], a[4], a[5] );
+	}
+	
+	public function next() : Null<Certificate> {
+		var n = cert_get_next(__x);
+		return n == null ? null : new Certificate( n, __h==null ? this : __h );
+	}
+
+	public function add( pem : String ) : Void {
+		cert_add_pem(__x,untyped pem.__s);
+	}
+
+	public function addDER( der : haxe.io.Bytes ) : Void {
+		cert_add_der(__x,der.getData());
+	}
+
+	private static var cert_load_defaults = neko.Lib.load("ssl", "cert_load_defaults",0);
+	private static var cert_load_file = neko.Lib.load("ssl", "cert_load_file",1);
+	private static var cert_load_path = neko.Lib.load("ssl","cert_load_path",1);
+	private static var cert_get_subject = neko.Lib.load("ssl", "cert_get_subject", 2);
+	private static var cert_get_issuer = neko.Lib.load("ssl","cert_get_issuer",2);
+	private static var cert_get_altnames = neko.Lib.load("ssl","cert_get_altnames",1);
+	private static var cert_get_notbefore = neko.Lib.load("ssl","cert_get_notbefore",1);
+	private static var cert_get_notafter = neko.Lib.load("ssl","cert_get_notafter",1);
+	private static var cert_get_next = neko.Lib.load("ssl","cert_get_next",1);
+	private static var cert_add_pem = neko.Lib.load("ssl","cert_add_pem",2);
+	private static var cert_add_der = neko.Lib.load("ssl","cert_add_der",2);
+	
+
+}

+ 22 - 0
std/neko/_std/sys/ssl/Digest.hx

@@ -0,0 +1,22 @@
+package sys.ssl;
+
+@:coreApi
+class Digest {
+	
+	public static function make( data : haxe.io.Bytes, alg : DigestAlgorithm ) : haxe.io.Bytes {
+		return haxe.io.Bytes.ofData( dgst_make( data.getData(), untyped alg.__s ) );
+	}
+	
+	public static function sign( data : haxe.io.Bytes, privKey : Key, alg : DigestAlgorithm ) : haxe.io.Bytes {
+		return haxe.io.Bytes.ofData( dgst_sign( data.getData(), @:privateAccess privKey.__k, untyped alg.__s ) );
+	}
+	
+	public static function verify( data : haxe.io.Bytes, signature : haxe.io.Bytes, pubKey : Key, alg : DigestAlgorithm ) : Bool{
+		return dgst_verify( data.getData(), signature.getData(), @:privateAccess pubKey.__k, untyped alg.__s );
+	}
+
+	private static var dgst_make = neko.Lib.load("ssl","dgst_make",2);
+	private static var dgst_sign = neko.Lib.load("ssl","dgst_sign",3);
+	private static var dgst_verify = neko.Lib.load("ssl","dgst_verify",4);
+
+}

+ 34 - 0
std/neko/_std/sys/ssl/Key.hx

@@ -0,0 +1,34 @@
+package sys.ssl;
+
+private typedef PKEY = Dynamic;
+
+@:coreApi
+class Key {
+	
+	private var __k : PKEY;
+
+	private function new( k : PKEY ){
+		__k = k;
+	}
+	
+	public static function loadFile( file : String, ?isPublic : Bool, ?pass : String ) : Key {
+		var data = sys.io.File.getBytes( file );
+		var str = neko.Lib.stringReference(data);
+		if( str.indexOf("-----BEGIN ") >= 0 )
+			return readPEM( str, isPublic==true, pass );
+		else
+			return readDER( data, isPublic==true );
+	}
+	
+	public static function readPEM( data : String, isPublic : Bool, ?pass : String ) : Key {
+		return new Key( key_from_pem( untyped data.__s, isPublic, pass == null ? null : untyped pass.__s ) );
+	}
+
+	public static function readDER( data : haxe.io.Bytes, isPublic : Bool ) : Key {
+		return new Key( key_from_der( data.getData(), isPublic ) );
+	}
+
+	private static var key_from_pem = neko.Lib.load("ssl","key_from_pem",3);
+	private static var key_from_der = neko.Lib.load("ssl","key_from_der",2);
+
+}

+ 288 - 0
std/neko/_std/sys/ssl/Socket.hx

@@ -0,0 +1,288 @@
+package sys.ssl;
+
+private typedef SocketHandle = Dynamic;
+private typedef CTX = Dynamic;
+private typedef SSL = Dynamic;
+
+private class SocketInput extends haxe.io.Input {
+	@:allow(sys.ssl.Socket) private var __s : Socket;
+
+	public function new( s : Socket ) {
+		this.__s = s;
+	}
+
+	public override function readByte() {
+		return try {
+			__s.handshake();
+			ssl_recv_char( @:privateAccess __s.ssl );
+		} catch( e : Dynamic ) {
+			if( e == "Blocking" )
+				throw haxe.io.Error.Blocked;
+			else if( __s == null )
+				throw haxe.io.Error.Custom(e);
+			else
+				throw new haxe.io.Eof();
+		}
+	}
+
+	public override function readBytes( buf : haxe.io.Bytes, pos : Int, len : Int ) : Int {
+		var r : Int;
+		if( __s == null )
+			throw "Invalid handle";
+		try {
+			__s.handshake();
+			r = ssl_recv(  @:privateAccess __s.ssl, buf.getData(), pos, len );
+		} catch( e : Dynamic ) {
+			if( e == "Blocking" )
+				throw haxe.io.Error.Blocked;
+			else
+				throw haxe.io.Error.Custom(e);
+		}
+		if( r == 0 )
+			throw new haxe.io.Eof();
+		return r;
+	}
+
+	public override function close() {
+		super.close();
+		if( __s != null ) __s.close();
+	}
+
+	private static var ssl_recv = neko.Lib.load( "ssl", "ssl_recv", 4 );
+	private static var ssl_recv_char = neko.Lib.load( "ssl", "ssl_recv_char", 1 );
+
+}
+
+private class SocketOutput extends haxe.io.Output {
+	@:allow(sys.ssl.Socket) private var __s : Socket;
+
+	public function new( s : Socket ) {
+		this.__s = s;
+	}
+
+	public override function writeByte( c : Int ) {
+		if( __s == null )
+			throw "Invalid handle";
+		try {
+			__s.handshake();
+			ssl_send_char( @:privateAccess __s.ssl, c);
+		} catch( e : Dynamic ) {
+			if( e == "Blocking" )
+				throw haxe.io.Error.Blocked;
+			else
+				throw haxe.io.Error.Custom(e);
+		}
+	}
+
+	public override function writeBytes( buf : haxe.io.Bytes, pos : Int, len : Int) : Int {
+		return try {
+			__s.handshake();
+			ssl_send( @:privateAccess __s.ssl, buf.getData(), pos, len);
+		} catch( e : Dynamic ) {
+			if( e == "Blocking" )
+				throw haxe.io.Error.Blocked;
+			else
+				throw haxe.io.Error.Custom(e);
+		}
+	}
+
+	public override function close() {
+		super.close();
+		if( __s != null ) __s.close();
+	}
+
+	private static var ssl_send_char = neko.Lib.load( "ssl", "ssl_send_char", 2 );
+	private static var ssl_send = neko.Lib.load( "ssl", "ssl_send", 4 );
+}
+
+@:coreApi
+class Socket extends sys.net.Socket {
+	
+	public static var DEFAULT_VERIFY_CERT : Null<Bool> = true;
+
+	public static var DEFAULT_CA : Null<Certificate>;
+	
+	private var ctx : CTX;
+	private var ssl : SSL;
+	
+	public var verifyCert : Null<Bool>;
+	private var caCert : Null<Certificate>;
+	private var hostname : String;
+
+	private var ownCert : Null<Certificate>;
+	private var ownKey : Null<Key>;
+	private var altSNIContexts : Null<Array<{match: String->Bool, key: Key, cert: Certificate}>>;
+	private var sniCallback : Dynamic;
+	private var handshakeDone : Bool;
+
+	private override function init() : Void {
+		__s = socket_new( false );
+		input = new SocketInput( this );
+		output = new SocketOutput( this );
+		if( DEFAULT_VERIFY_CERT && DEFAULT_CA == null ){
+			try {
+				DEFAULT_CA = Certificate.loadDefaults();
+			}catch( e : Dynamic ){}
+		}
+		verifyCert = DEFAULT_VERIFY_CERT;
+		caCert = DEFAULT_CA;
+	}
+
+	public override function connect(host : sys.net.Host, port : Int) : Void {
+		try {
+			ctx = buildSSLContext( false );
+			ssl = ssl_new( ctx );
+			ssl_set_socket( ssl, __s );
+			handshakeDone = false;
+			if( hostname == null )
+				hostname = host.host;
+			if( hostname != null )
+				ssl_set_hostname( ssl, untyped hostname.__s );
+			socket_connect( __s, host.ip, port );
+			handshake();
+		} catch( s : String ) {
+			if( s == "std@socket_connect" )
+				throw "Failed to connect on "+host.host+":"+port;
+			else
+				neko.Lib.rethrow(s);
+		} catch( e : Dynamic ) {
+			neko.Lib.rethrow(e);
+		}
+	}
+
+	public function handshake() : Void {
+		if( !handshakeDone ){
+			try {
+				ssl_handshake( ssl );
+				handshakeDone = true;
+			} catch( e : Dynamic ) {
+				if( e == "Blocking" )
+					throw haxe.io.Error.Blocked;
+				else
+					neko.Lib.rethrow( e );
+			}
+		}
+	}
+
+	public function setCA( cert : Certificate ) : Void {
+		caCert = cert;
+	}
+
+	public function setHostname( name : String ) : Void {
+		hostname = name;
+	}
+
+	public function setCertificate( cert : Certificate, key : Key ) : Void {
+		ownCert = cert;
+		ownKey = key;
+	}
+
+	public override function read() : String {
+		handshake();
+		var b = ssl_read( ssl );
+		if( b == null )
+			return "";
+		return new String(cast b);
+	}
+
+	public override function write( content : String ) : Void {
+		handshake();
+		ssl_write( ssl, untyped content.__s );
+	}
+
+	public override function close() : Void {
+		if( ssl != null ) ssl_close( ssl );
+		if( ctx != null ) conf_close( ctx );
+		if( altSNIContexts != null )
+			sniCallback = null;
+		socket_close( __s );
+		var input : SocketInput = cast input;
+		var output : SocketOutput = cast output;
+		@:privateAccess input.__s = output.__s = null;
+		input.close();
+		output.close();
+	}
+
+	public function addSNICertificate( cbServernameMatch : String->Bool, cert : Certificate, key : Key ) : Void {
+		if( altSNIContexts == null )
+			altSNIContexts = [];
+		altSNIContexts.push( {match: cbServernameMatch, cert: cert, key: key} );
+	}
+
+	public override function bind( host : sys.net.Host, port : Int ) : Void {
+		ctx = buildSSLContext( true );
+
+		socket_bind( __s, host.ip, port );
+	}
+
+	public override function accept() : Socket {
+		var c = socket_accept( __s );
+		var ssl = ssl_new( ctx );
+		ssl_set_socket( ssl, c );
+
+		var s = Type.createEmptyInstance( sys.ssl.Socket );
+		s.__s = c;
+		s.ssl = ssl;
+		s.input = new SocketInput(s);
+		s.output = new SocketOutput(s);
+		s.handshakeDone = false;
+
+		return s;
+	}
+
+	public function peerCertificate() : sys.ssl.Certificate {
+		var x = ssl_get_peer_certificate( ssl );
+		return x==null ? null : new sys.ssl.Certificate( x );
+	}
+
+	private function buildSSLContext( server : Bool ) : CTX {
+		var ctx : CTX = conf_new( server );
+
+		if( ownCert != null && ownKey != null )
+			conf_set_cert( ctx, @:privateAccess ownCert.__x, @:privateAccess ownKey.__k );
+
+		if ( altSNIContexts != null ) {
+			sniCallback = function(servername) {
+				var servername = new String(cast servername);
+				for( c in altSNIContexts ){
+					if( c.match(servername) )
+						return @:privateAccess {key: c.key.__k, cert: c.cert.__x};
+				}
+				if( ownKey != null && ownCert != null )
+					return @:privateAccess { key: ownKey.__k, cert: ownCert.__x };
+				return null;
+			}
+			conf_set_servername_callback( ctx, sniCallback );
+		}
+
+		if ( caCert != null ) 
+			conf_set_ca( ctx, caCert == null ? null : @:privateAccess caCert.__x  );
+		conf_set_verify( ctx, verifyCert );
+		
+		return ctx;
+	}
+	
+	private static var ssl_new = neko.Lib.load( "ssl", "ssl_new", 1 );
+	private static var ssl_close = neko.Lib.load( "ssl", "ssl_close", 1 );
+	private static var ssl_handshake = neko.Lib.load( "ssl", "ssl_handshake", 1 );
+	private static var ssl_set_socket = neko.Lib.load( "ssl", "ssl_set_socket", 2 );
+	private static var ssl_set_hostname = neko.Lib.load( "ssl", "ssl_set_hostname", 2 );
+	private static var ssl_get_peer_certificate = neko.Lib.load( "ssl", "ssl_get_peer_certificate", 1 );
+
+	private static var ssl_read = neko.Lib.load( "ssl", "ssl_read", 1 );
+	private static var ssl_write = neko.Lib.load( "ssl", "ssl_write", 2 );
+
+	private static var conf_new = neko.Lib.load( "ssl", "conf_new", 1 );
+	private static var conf_close = neko.Lib.load( "ssl", "conf_close", 1 );
+	private static var conf_set_ca = neko.Lib.load( "ssl", "conf_set_ca", 2 );
+	private static var conf_set_verify = neko.Lib.load( "ssl", "conf_set_verify", 2 );
+	private static var conf_set_cert = neko.Lib.load( "ssl", "conf_set_cert", 3 );
+	private static var conf_set_servername_callback = neko.Lib.load( "ssl", "conf_set_servername_callback", 2 );
+
+	private static var socket_new = neko.Lib.load("std","socket_new",1);
+	private static var socket_close = neko.Lib.load("std","socket_close",1);
+	private static var socket_connect = neko.Lib.load("std","socket_connect",3);
+	private static var socket_bind = neko.Lib.load("std","socket_bind",3);
+	private static var socket_accept = neko.Lib.load("std","socket_accept",1);
+
+}

+ 1 - 1
std/neko/net/ServerLoop.hx

@@ -64,7 +64,7 @@ class ServerLoop<ClientData> {
 	public var updateTime : Float;
 	public var updateTime : Float;
 
 
 	var newData : Socket -> ClientData;
 	var newData : Socket -> ClientData;
-	var socks : Array<Socket>;
+	var socks : Array<sys.net.Socket>;
 	public var clients : List<ClientData>;
 	public var clients : List<ClientData>;
 
 
 	/**
 	/**

+ 39 - 0
std/sys/ssl/Certificate.hx

@@ -0,0 +1,39 @@
+package sys.ssl;
+
+extern class Certificate {
+	
+	public static function loadFile( file : String ) : Certificate;
+	
+	public static function loadPath( path : String ) : Certificate;
+
+	public static function fromString( str : String ) : Certificate;
+	
+	public static function loadDefaults() : Certificate;
+
+	public var commonName(get,null) : Null<String>;
+
+	public var altNames(get,null) : Array<String>;
+	
+	public var notBefore(get,null) : Date;
+	
+	public var notAfter(get,null) : Date;
+	
+	public function subject( field : String ) : Null<String>;
+	
+	public function issuer( field : String ) : Null<String>;
+	
+	public function next() : Null<Certificate>;
+
+	public function add( pem : String ) : Void;
+
+	public function addDER( der : haxe.io.Bytes ) : Void;
+
+	private function get_commonName() : Null<String>;
+
+	private function get_altNames() : Array<String>;
+
+	private function get_notBefore() : Date;
+
+	private function get_notAfter() : Date;
+
+}

+ 11 - 0
std/sys/ssl/Digest.hx

@@ -0,0 +1,11 @@
+package sys.ssl;
+
+extern class Digest {
+	
+	static function make( data : haxe.io.Bytes, alg : DigestAlgorithm ) : haxe.io.Bytes;
+	
+	static function sign( data : haxe.io.Bytes, privKey : Key, alg : DigestAlgorithm ) : haxe.io.Bytes;
+	
+	static function verify( data : haxe.io.Bytes, signature : haxe.io.Bytes, pubKey : Key, alg : DigestAlgorithm ) : Bool;
+
+}

+ 12 - 0
std/sys/ssl/DigestAlgorithm.hx

@@ -0,0 +1,12 @@
+package sys.ssl;
+
+@:enum
+abstract DigestAlgorithm(String) to String {
+	var MD5 = "MD5";
+	var SHA1 = "SHA1";
+	var SHA224 = "SHA224";
+	var SHA256 = "SHA256";
+	var SHA384 = "SHA384";
+	var SHA512 = "SHA512";
+	var RIPEMD160 = "RIPEMD160";
+}

+ 11 - 0
std/sys/ssl/Key.hx

@@ -0,0 +1,11 @@
+package sys.ssl;
+
+extern class Key {
+	
+	static function loadFile( file : String, ?isPublic : Bool, ?pass : String ) : Key;
+	
+	static function readPEM( data : String, isPublic : Bool, ?pass : String ) : Key;
+
+	static function readDER( data : haxe.io.Bytes, isPublic : Bool ) : Key;
+
+}

+ 50 - 0
std/sys/ssl/Socket.hx

@@ -0,0 +1,50 @@
+package sys.ssl;
+
+/**
+	A TLS socket class : allow you to both connect to a given server and exchange messages or start your own server and wait for connections.
+**/
+extern class Socket extends sys.net.Socket {
+
+	static var DEFAULT_VERIFY_CERT : Null<Bool>;
+
+	static var DEFAULT_CA : Null<sys.ssl.Certificate>;
+
+	/**
+		Define if peer certificate is verified during SSL handshake.
+	**/
+	var verifyCert : Null<Bool>;
+
+	function new() : Void;
+
+	/**
+		Perform the SSL handshake.
+	**/
+	function handshake() : Void;
+	
+	/**
+		Configure the certificate chain for peer certificate verification.
+	**/	
+	function setCA( cert : sys.ssl.Certificate ) : Void;
+
+	/**
+		Configure the hostname for Server Name Indication TLS extension.
+	**/
+	function setHostname( name : String ) : Void;
+
+	/**
+		Configure own certificate and private key.
+	**/
+	function setCertificate( cert : Certificate, key : Key ) : Void;
+
+	/**
+		Configure additionals certificates and private keys for Server Name Indication extension.
+		The callback may be called during handshake to determine the certificate to use.
+	**/
+	function addSNICertificate( cbServernameMatch : String->Bool, cert : Certificate, key : Key ) : Void;
+	
+	/**
+		Return the certificate received from the other side of a connection.
+	**/
+	function peerCertificate() : sys.ssl.Certificate;
+
+}

+ 4 - 0
tests/unit/src/unitstd/Https.unit.hx

@@ -0,0 +1,4 @@
+#if (cpp || (neko && !macro && !interp))
+var r = haxe.Http.requestUrl("https://raw.githubusercontent.com/HaxeFoundation/haxe/development/tests/unit/res1.txt");
+r == "Héllo World !";
+#end