1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
  
14
  
15
  
16
  
17
  
18
  
19
  
20
  
21
  
22
  
23
  
24
  
25
  
26
  
27
  
28
  
29
  
30
  
31
  
32
  
33
  
34
  
35
  
36
  
37
  
38
  
39
  
40
  
41
  
42
  
43
  
44
  
45
  
46
  
47
  
48
  
49
  
50
  
51
  
52
  
53
  
54
  
55
  
56
  
57
  
58
  
59
  
60
  
61
  
62
  
63
  
64
  
65
  
66
  
67
  
68
  
69
  
70
  
71
  
72
  
73
  
74
  
75
  
76
  
77
  
78
  
79
  
80
  
81
  
82
  
83
  
84
  
85
  
86
  
87
  
88
  
89
  
90
  
91
  
92
  
93
  
94
  
95
  
96
  
97
  
98
  
99
  
100
  
101
  
102
  
103
  
104
  
105
  
106
  
107
  
108
  
109
  
110
  
#pike __REAL_VERSION__ 
#require constant(SSL.Port) 
 
inherit SSL.Port; 
 
import "."; 
 
int portno; 
string interface; 
function(Request:void) callback; 
 
//! 
object|function|program request_program=Request; 
 
//! A very simple SSL server. Binds a port and calls a callback with 
//! @[request_program] objects. 
 
//! Create a HTTPS (HTTP over SSL) server. 
//! 
//! @param callback 
//!   The function run when a request is received. 
//!   takes one argument of type @[Request]. 
//! @param port 
//!   The port number to bind to, defaults to 443. 
//! @param interface 
//!   The interface address to bind to. 
//! @param key 
//!   An optional SSL secret key, provided in binary format, such 
//!   as that created by @[Standards.PKCS.RSA.private_key()]. 
//! @param certificate 
//!   An optional SSL certificate or chain of certificates with the host 
//!   certificate first, provided in binary format. 
//! @param reuse_port 
//!   If true, enable SO_REUSEPORT if the OS supports it. See 
//!   @[Stdio.Port.bind] for more information 
protected void create(function(Request:void) callback, 
                      void|int port, 
                      void|string interface, 
                      void|string|Crypto.Sign.State key, 
                      void|string|array(string) certificate, 
                      void|int reuse_port) 
{ 
  ::create(); 
 
  portno = port || 443; 
  this::callback=callback; 
  this::interface=interface; 
 
  if( key && certificate ) 
  { 
    if( stringp(certificate) ) 
      certificate = ({ certificate }); 
    ctx->add_cert( key, certificate, ({"*"}) ); 
  } 
  else 
    set_default_keycert(); 
 
  if (!bind(portno, new_connection, this::interface, reuse_port)) 
    error("Failed to bind port %s%d: %s\n", 
          interface?interface+":":"", portno, strerror(errno())); 
} 
 
protected void _destruct() { close(); } 
 
//! The port accept callback 
protected void new_connection() 
{ 
   SSL.File fd=accept(); 
   Request r=request_program(); 
   r->attach_fd(fd,this,callback); 
} 
 
protected void set_default_keycert() 
{ 
  foreach(({ Crypto.RSA(), Crypto.DSA(), 
#if constant(Crypto.ECC.Curve) 
             Crypto.ECC.SECP_521R1.ECDSA(), 
#endif 
          }), Crypto.Sign private_key) 
  { 
    switch(private_key->name()) { 
    case "RSA": 
      private_key->generate_key(4096); 
      break; 
    case "DSA": 
      private_key->generate_key(4096, 160); 
      break; 
    default: 
      // ECDSA. 
      private_key->generate_key(); 
      break; 
    } 
 
    mapping a = ([ 
      "organizationName" : "Pike TLS server", 
      "commonName" : "*", 
    ]); 
 
    string c = Standards.X509.make_selfsigned_certificate(private_key, 
                                                          3600*24*365, a); 
 
    ctx->add_cert( private_key, ({ c }) ); 
  } 
} 
 
protected string _sprintf(int t) { 
  return t=='O' && sprintf("%O(%O:%d)", this_program, interface, portno); 
}