Better SSL support

svn: r12396
This commit is contained in:
Jay McCarthy 2008-11-11 23:31:26 +00:00
parent 9c174affa7
commit fd6dfdbbc4
6 changed files with 68 additions and 144 deletions

View File

@ -0,0 +1,6 @@
#!/bin/sh
openssl genrsa -des3 -out private-key.pem 1024
openssl rsa -in private-key.pem -out private-key.pem
chmod 400 private-key.pem
openssl req -new -x509 -nodes -sha1 -days 365 -key private-key.pem > server-cert.pem

View File

@ -1,6 +1,10 @@
#lang scheme/base
(require mzlib/cmdline
mzlib/pregexp)
#lang scheme
(require scheme/cmdline
scheme/unit
mzlib/pregexp
net/tcp-sig
net/tcp-unit
net/ssl-tcp-unit)
(require "../configuration/configuration-table.ss"
(except-in "../web-server.ss" serve)
"../web-config-unit.ss")
@ -13,11 +17,19 @@
(cdr x)
default)))
(define ssl (make-parameter #f))
(define port (make-parameter 80))
(define configuration@
(parse-command-line
"plt-web-server"
(current-command-line-arguments)
`((once-each
[("--ssl")
,(lambda (flag)
(port 443)
(ssl #t))
("Run with SSL using server-cert.pem and private-key.pem in the current directory, with 443 as the default port.")]
[("-f" "--configuration-table")
,(lambda (flag file-name)
(cond
@ -28,8 +40,8 @@
[else (cons 'config (string->path file-name))]))
("Use an alternate configuration table" "file-name")]
[("-p" "--port")
,(lambda (flag port)
(cons 'port (string->number port)))
,(lambda (flag the-port)
(port (string->number the-port)))
("Use an alternate network port." "port")]
[("-a" "--ip-address")
,(lambda (flag ip-address)
@ -46,11 +58,21 @@
(lambda (flags)
(configuration-table->web-config@
(extract-flag 'config flags default-configuration-table-path)
#:port (extract-flag 'port flags #f)
#:port (port)
#:listen-ip (extract-flag 'ip-address flags #f)))
'()))
(define (serve)
(serve/web-config@ configuration@))
(serve/web-config@
configuration@
#:tcp@ (if (ssl)
(let ()
(define-unit-binding ssl-tcp@
(make-ssl-tcp@ (build-path (current-directory) "server-cert.pem")
(build-path (current-directory) "private-key.pem")
#f #f #f #f #f)
(import) (export tcp^))
ssl-tcp@)
tcp@)))
(provide serve)

View File

@ -67,70 +67,25 @@ Second, if you want to make your own Scheme start-up script, you can write:
@section[#:tag "faq:https"]{How do I set up the server to use HTTPS?}
The essence of the solution to this problem is to use an SSL TCP implementation as provided by @schememodname[net/ssl-tcp-unit]. Many of the functions that start the Web Server are parameterized by a @scheme[tcp@] unit. If you pass an SSL unit, then the server will be serving HTTPS. However, to do this, you must write your own start up script. Here's a simple example:
This requires an SSL certificate and private key. This is very platform specific, but we will provide
the details for using OpenSSL on UNIX:
@(require (for-label scheme/unit)
(for-label net/ssl-tcp-unit)
(for-label net/tcp-sig)
(for-label net/tcp-unit)
(for-label web-server/web-server)
(for-label web-server/web-server-unit)
(for-label web-server/web-server-sig)
(for-label web-server/web-config-sig)
(for-label web-server/web-config-unit)
(for-label web-server/configuration/namespace))
@commandline{openssl genrsa -des3 -out private-key.pem 1024}
@schememod[
scheme
This will generate a new private key, but it will have a passphrase on it. You can remove this via:
@code:comment{Load the appropriate libraries to reimplement server}
(require scheme/unit
net/ssl-tcp-unit
net/tcp-sig
net/tcp-unit
(only-in web-server/web-server do-not-return)
web-server/web-server-unit
web-server/web-server-sig
web-server/web-config-sig
web-server/web-config-unit
web-server/configuration/namespace)
@commandline{openssl rsa -in private-key.pem -out private-key.pem}
@commandline{chmod 400 private-key.pem}
@code:comment{Define the necessary parameters.}
(define port-no 8443)
(define SSL-path (find-system-path 'home-dir))
Now, we generate a self-signed certificate:
@code:comment{Load the standard configuration file, but augment the port.}
(define configuration
(configuration-table->web-config@
(build-path (collection-path "web-server")
"default-web-root"
"configuration-table.ss")
#:port port-no))
@commandline{openssl req -new -x509 -nodes -sha1 -days 365 -key private-key.pem > server-cert.pem}
@code:comment{The configuration is a unit and this lets us treat it as one.}
(define-unit-binding config@ configuration
(import) (export web-config^))
(Each certificate authority has different instructions for generating certificate signing requests.)
@code:comment{This loads the SSL TCP interface with the appropriate keys.}
(define-unit-binding ssl-tcp@
(make-ssl-tcp@ (build-path SSL-path "server-cert.pem")
(build-path SSL-path "private-key.pem")
#f #f #f #f #f)
(import) (export tcp^))
We can now start the server with:
@code:comment{Combine the configuration with the TCP interface to get a server!}
(define-compound-unit/infer ssl-server@
(import)
(link ssl-tcp@ config@ web-server@)
(export web-server^))
@commandline{plt-web-server --ssl}
@code:comment{Invoke the server to get at what it provides.}
(define-values/invoke-unit/infer ssl-server@)
@code:comment{Run the server.}
(serve)
(do-not-return)
]
Running this script, rather than @exec{plt-web-server}, runs the server using SSL on port @scheme[port-no].
The certificate and private key are located in the @scheme[SSL-path] directory.
The Web Server will start on port 443 (which can be overridden with the @exec{-p} option) using the
@filepath{private-key.pem} and @filepath{server-cert.pem} we've created.

View File

@ -55,14 +55,16 @@ The following API is provided to customize the server instance:
One command-line utility is provided with the @|web-server|:
@commandline{plt-web-server [-f <file-name> -p <port> -a <ip-address>]}
@commandline{plt-web-server [-f <file-name> -p <port> -a <ip-address> --ssl]}
The optional file-name argument specifies the path to a
@scheme[configuration-table] S-expression (see
@secref["configuration-table.ss"].) If this is not provided, the
default configuration shipped with the server is used. The optional
port and ip-address arguments override the corresponding portions of
the @scheme[configuration-table].
the @scheme[configuration-table]. If the SSL option is provided, then
the server uses HTTPS with @filepath{server-cert.pem} and @filepath{private-key.pem}
in the current directory, with 443 as the default port.
The @scheme[configuration-table] is given to
@scheme[configuration-table->web-config@] and used to construct a
@ -139,7 +141,8 @@ from a given path:
a function that shuts down all of the server instances.
}
@defproc[(serve/web-config@ [config@ web-config^])
@defproc[(serve/web-config@ [config@ web-config^]
[#:tcp@ tcp@ tcp-unit^ raw:tcp@])
(-> void)]{
Starts the @web-server with the settings defined by the given @scheme[web-config^] unit.
@ -148,8 +151,7 @@ from a given path:
@schemeblock[
(serve/web-config@
(configuration-table->web-config@
default-configuration-table-path))
(do-not-return)]
default-configuration-table-path))]
}
@defproc[(do-not-return) void]{

View File

@ -1183,88 +1183,25 @@ This final task that we'll cover is using the server in HTTPS mode.
This requires an SSL certificate and private key. This is very platform specific, but we will provide
the details for using OpenSSL on UNIX:
@commandline{openssl genrsa -des3 -out host.key 1024}
@commandline{openssl genrsa -des3 -out private-key.pem 1024}
This will generate a new private key, but it will have a passphrase on it. You can remove this via:
@commandline{openssl rsa -in host.key -out host.key}
@commandline{chmod 400 host.key}
@commandline{openssl rsa -in private-key.pem -out private-key.pem}
@commandline{chmod 400 private-key.pem}
Now, we generate a self-signed certificate:
@commandline{openssl req -new -x509 -nodes -sha1 -days 365 -key host.key > host.cert}
@commandline{openssl req -new -x509 -nodes -sha1 -days 365 -key private-key.pem > server-cert.pem}
(Each certificate authority has different instructions for generating certificate signing requests.)
If we move these files into our home directory:
@commandline{mv host.key host.cert ~/}
We can now start the server with:
We can now start the server with the following incantation:
@commandline{plt-web-server --ssl}
@(require (for-label scheme/unit)
(for-label net/ssl-tcp-unit)
(for-label net/tcp-sig)
(for-label net/tcp-unit)
(for-label web-server/web-server)
(for-label web-server/web-server-unit)
(for-label web-server/web-server-sig)
(for-label web-server/web-config-sig)
(for-label web-server/web-config-unit)
(for-label web-server/configuration/namespace))
@schememod[
scheme
@code:comment{Load the appropriate libraries to reimplement server}
(require scheme/unit
net/ssl-tcp-unit
net/tcp-sig
net/tcp-unit
(only-in web-server/web-server do-not-return)
web-server/web-server-unit
web-server/web-server-sig
web-server/web-config-sig
web-server/web-config-unit
web-server/configuration/namespace)
@code:comment{Define the necessary parameters.}
(define port-no 8443)
(define SSL-path (find-system-path 'home-dir))
@code:comment{Load the standard configuration file, but augment the port.}
(define configuration
(configuration-table->web-config@
(build-path (collection-path "web-server")
"default-web-root"
"configuration-table.ss")
#:port port-no))
@code:comment{The configuration is a unit and this lets us treat it as one.}
(define-unit-binding config@ configuration
(import) (export web-config^))
@code:comment{This loads the SSL TCP interface with the appropriate keys.}
(define-unit-binding ssl-tcp@
(make-ssl-tcp@ (build-path SSL-path "host.cert")
(build-path SSL-path "host.key")
#f #f #f #f #f)
(import) (export tcp^))
@code:comment{Combine the configuration with the TCP interface to get a server!}
(define-compound-unit/infer ssl-server@
(import)
(link ssl-tcp@ config@ web-server@)
(export web-server^))
@code:comment{Invoke the server to get at what it provides.}
(define-values/invoke-unit/infer ssl-server@)
@code:comment{Run the server.}
(serve)
(do-not-return)
]
This is, admittedly, not the simplest imaginable way of setting up a server, but it gets the job done.
The Web Server will start on port 443 (which can be overridden with the @exec{-p} option) using the
@filepath{private-key.pem} and @filepath{server-cert.pem} we've created.
@section{Moving Forward}

View File

@ -36,7 +36,7 @@
#:initial-connection-timeout number?)
(-> void))]
[do-not-return (-> void)]
[serve/web-config@ (unit? . -> . (-> void?))])
[serve/web-config@ ((unit?) (#:tcp@ unit?) . ->* . (-> void?))])
(define (do-not-return)
(semaphore-wait (make-semaphore 0)))
@ -101,7 +101,9 @@
(for-each apply shutdowns)))
; serve/config@ : configuration -> (-> void)
(define (serve/web-config@ config@)
(define (serve/web-config@ config@ #:tcp@ [tcp@ raw:tcp@])
(define-unit-binding a-tcp@
tcp@ (import) (export tcp^))
(define-unit m@ (import web-server^) (export)
(init-depend web-server^)
(serve))
@ -109,5 +111,5 @@
(invoke-unit
(compound-unit/infer
(import)
(link raw:tcp@ c@ web-server@ m@)
(link a-tcp@ c@ web-server@ m@)
(export))))