SNI support for OpenSSL egg (r2) added by murphy_tcc on Sun Aug 20 19:49:38 2017

Index: openssl.scm
===================================================================
--- openssl.scm	(revision 33673)
+++ openssl.scm	(working copy)
@@ -244,6 +244,15 @@
                 #f)))))
        (apply ssl-abort loc sym args)))))
 
+(define (ssl-set-tlsext-hostname! ssl hostname)
+  (ssl-clear-error)
+  (ssl-result-or-abort
+   'ssl-set-tlsext-hostname! ssl
+   ((foreign-lambda int "SSL_set_tlsext_host_name" c-pointer c-string)
+    ssl hostname) #f
+   hostname)
+  (void))
+
 (define (ssl-set-fd! ssl fd)
   (ssl-clear-error)
   (ssl-result-or-abort
@@ -553,18 +562,29 @@
 (define ssl-set-connect-state! (foreign-lambda void "SSL_set_connect_state" c-pointer))
 
 ;; connect to SSL server
-(define (ssl-connect hostname #!optional port (ctx 'sslv2-or-v3))
-  (receive (tcp-in tcp-out)
-    (tcp-connect hostname port)
-    (let* ((fd (net-unwrap-tcp-ports tcp-in tcp-out))
-           (ctx
-            (if (ssl-client-context? ctx)
-                (ssl-unwrap-client-context ctx)
-                (ssl-ctx-new ctx #f)))
-           (ssl
-            (ssl-new ctx)))
-      (ssl-set-connect-state! ssl)
-      (ssl-make-i/o-ports ctx fd ssl tcp-in tcp-out))))
+(define (ssl-connect hostname #!optional port (ctx 'sslv2-or-v3) (sni-name hostname))
+  (let* ((ctx
+          (if (ssl-client-context? ctx)
+              (ssl-unwrap-client-context ctx)
+              (ssl-ctx-new ctx #f)))
+         (ssl (ssl-new ctx))
+         (success? #f))
+    (dynamic-wind
+      void
+      (lambda ()
+        (when sni-name
+          (ssl-set-tlsext-hostname! ssl sni-name))
+        (ssl-set-connect-state! ssl)
+        (receive (tcp-in tcp-out)
+          (tcp-connect hostname port)
+          (receive (ssl-in ssl-out)
+            (ssl-make-i/o-ports ctx (net-unwrap-tcp-ports tcp-in tcp-out) ssl tcp-in tcp-out)
+            (set! success? #t)
+            (values ssl-in ssl-out))))
+      (lambda ()
+        (unless success?
+          (ssl-free ssl)
+          (set! ssl #f))))))
 
 ;; create listener/SSL server context
 (define-record-type ssl-listener
@@ -779,8 +799,8 @@
     (ssl-set-verify! ctx verify?)
     ctx))
 
-(define (ssl-connect* #!rest args #!key hostname port)
-  (ssl-connect hostname port (apply ssl-make-client-context* args)))
+(define (ssl-connect* #!rest args #!key hostname port (sni-name hostname))
+  (ssl-connect hostname port (apply ssl-make-client-context* args) sni-name))
 
 (define (ssl-listen* #!key hostname (port 0) (backlog 4) (protocol 'tlsv12) (cipher-list "DEFAULT") certificate private-key (private-key-type 'rsa) private-key-asn1? certificate-authorities certificate-authority-directory (verify? #f))
   (unless (or certificate-authorities certificate-authority-directory)
@@ -795,7 +815,7 @@
     (ssl-set-verify! ear verify?)
     ear))
 
-(define (ssl-start* server? tcp-in tcp-out #!key (protocol 'tlsv12) (cipher-list "DEFAULT") certificate private-key (private-key-type 'rsa) private-key-asn1? certificate-authorities certificate-authority-directory (verify? (not server?)))
+(define (ssl-start* server? tcp-in tcp-out #!key (protocol 'tlsv12) (cipher-list "DEFAULT") certificate private-key (private-key-type 'rsa) private-key-asn1? certificate-authorities certificate-authority-directory (verify? (not server?)) sni-name)
   (unless (or certificate-authorities certificate-authority-directory)
     (set! certificate-authority-directory (ssl-default-certificate-authority-directory)))
   ;; ssl-wrap-client-context only serves a technical purpose here,
@@ -813,7 +833,10 @@
            (ssl (ssl-new (ssl-unwrap-client-context ctx))))
       (if server?
         (ssl-set-accept-state! ssl)
-        (ssl-set-connect-state! ssl))
+        (begin
+          (when sni-name
+            (ssl-set-tlsext-hostname! ssl sni-name))
+          (ssl-set-connect-state! ssl)))
       (ssl-make-i/o-ports ctx fd ssl tcp-in tcp-out))))
 
 )