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 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
|
#pike __REAL_VERSION__
#require constant(SSL.Cipher)
//! Dummy HTTPS server/client
#ifndef PORT
#define PORT 25678
#endif
#ifndef CIPHER_BITS
#define CIPHER_BITS 112
#endif
#ifndef RSA_BITS
#define RSA_BITS 4096
#endif
#ifndef DSA_BITS
#define DSA_BITS 2048
#endif
#ifndef KE_MODE
#define KE_MODE 1
#endif
#ifndef HOST
#define HOST "127.0.0.1"
#endif
#ifdef SSL3_DEBUG
#define SSL3_DEBUG_MSG(X ...) werror(X)
#else /*! SSL3_DEBUG */
#define SSL3_DEBUG_MSG(X ...)
#endif /* SSL3_DEBUG */
class MyContext
{
inherit SSL.Context;
SSL.Alert alert_factory(.Connection con,
int level, int description,
SSL.Constants.ProtocolVersion version,
string|void message)
{
if (message && description) {
werror("ALERT [%s: %d:%d]: %s",
SSL.Constants.fmt_version(version),
level, description, message);
}
return ::alert_factory(con, level, description, version, message);
}
}
#ifndef HTTPS_CLIENT
SSL.Port port;
void my_accept_callback(object f)
{
Conn(port->accept());
}
#endif
class Conn {
object sslfile;
string message =
"HTTP/1.0 200 Ok\r\n"
"Connection: close\r\n"
"Content-Length: 132\r\n"
"Content-Type: text/html; charset=ISO-8859-1\r\n"
"Date: Thu, 01 Jan 1970 00:00:01 GMT\r\n"
"Server: Bare-Bones\r\n"
"\r\n"
"<html><head><title>SSL-3 server</title></head>\n"
"<body><h1>This is a minimal SSL-3 http server</h1>\n"
"<hr><it>/nisse</it></body></html>\n";
int index = 0;
void write_callback()
{
if (index < sizeof(message))
{
int written = sslfile->write(message[index..]);
if (written > 0)
index += written;
else
sslfile->close();
}
if (index == sizeof(message))
sslfile->close();
}
void read_callback(mixed id, string data)
{
SSL3_DEBUG_MSG("Received: '" + data + "'\n");
sslfile->set_write_callback(write_callback);
}
protected void create(object f)
{
sslfile = f;
sslfile->set_nonblocking(read_callback, 0, 0);
}
}
class Client
{
constant request =
"HEAD / HTTP/1.0\r\n"
"Host: " HOST ":" + PORT + "\r\n"
"\r\n";
SSL.File ssl;
int sent;
void write_cb()
{
int bytes = ssl->write(request[sent..]);
if (bytes > 0) {
sent += bytes;
} else if (sent < 0) {
exit(17, "Failed to write data: %s\n", strerror(ssl->errno()));
}
if (sent == sizeof(request)) {
ssl->set_write_callback(UNDEFINED);
}
}
void got_data(mixed ignored, string data)
{
werror("Data: %O\n", data);
}
void con_closed()
{
exit(0, "Connection closed.\n");
}
protected void create(Stdio.File con)
{
SSL.Context ctx = MyContext();
// Make sure all cipher suites are available.
ctx->preferred_suites = ctx->get_suites(-1, 2);
werror("Starting\n");
ssl = SSL.File(con, ctx);
ssl->connect();
ssl->set_nonblocking(got_data, write_cb, con_closed);
}
}
string common_name;
void make_certificate(SSL.Context ctx, Crypto.Sign key, void|Crypto.Hash hash)
{
mapping attrs = ([
"organizationName" : "Test",
"commonName" : common_name,
]);
string cert = Standards.X509.make_selfsigned_certificate(key, 3600*24, attrs, 0, hash);
ctx->add_cert(key, ({ cert }), ({ "*" }));
}
int main()
{
#ifdef HTTPS_CLIENT
Stdio.File con = Stdio.File();
if (!con->connect(HOST, PORT)) {
werror("Failed to connect to server: %s\n", strerror(con->errno()));
return 17;
}
Client(con);
return -17;
#else
SSL.Context ctx = MyContext();
Crypto.Sign key;
common_name = gethostname();
common_name = (gethostbyname(common_name) || ({ common_name }))[0];
werror("Common name: %O\n", common_name);
werror("Generating RSA certificate (%d bits)...\n", RSA_BITS);
key = Crypto.RSA()->generate_key(RSA_BITS);
make_certificate(ctx, key);
// Compat with OLD clients.
make_certificate(ctx, key, Crypto.SHA1);
werror("Generating DSA certificate (%d bits)...\n", DSA_BITS);
catch {
// NB: Not all versions of Nettle support q sizes other than 160.
key = Crypto.DSA()->generate_key(DSA_BITS, 256);
make_certificate(ctx, key);
};
// Compat with OLD clients.
//
// The old FIPS standard maxed out at 1024 & 160 bits with SHA-1.
key = Crypto.DSA()->generate_key(1024, 160);
make_certificate(ctx, key, Crypto.SHA1);
#if constant(Crypto.ECC.Curve)
werror("Generating ECDSA certificate (%d bits)...\n", 521);
key = Crypto.ECC.SECP_521R1.ECDSA()->generate_key();
make_certificate(ctx, key);
// Compat with OLD clients.
//
// Unlikely to be needed, but the cost is minimal.
make_certificate(ctx, key, Crypto.SHA1);
#endif
// Make sure all cipher suites are available.
ctx->preferred_suites = ctx->get_suites(CIPHER_BITS, KE_MODE);
ctx->min_version = SSL.Constants.PROTOCOL_SSL_3_0;
SSL3_DEBUG_MSG("Cipher suites:\n%s",
.Constants.fmt_cipher_suites(ctx->preferred_suites));
SSL3_DEBUG_MSG("Certs:\n%O\n", ctx->get_certificates());
port = SSL.Port(ctx);
werror("Starting\n");
if (!port->bind(PORT, my_accept_callback))
{
Stdio.perror("");
return 17;
}
else {
werror("Listening on port %d.\n", PORT);
return -17;
}
#endif
}
|