diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/ssl/examples | |
download | otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2 otp-84adefa331c4159d432d22840663c38f155cd4c1.zip |
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/ssl/examples')
-rw-r--r-- | lib/ssl/examples/certs/Makefile | 24 | ||||
-rw-r--r-- | lib/ssl/examples/certs/Makefile.in | 80 | ||||
-rw-r--r-- | lib/ssl/examples/certs/ebin/.gitignore | 0 | ||||
-rw-r--r-- | lib/ssl/examples/certs/rnd/RAND | bin | 0 -> 512 bytes | |||
-rw-r--r-- | lib/ssl/examples/certs/src/make_certs.erl | 261 | ||||
-rw-r--r-- | lib/ssl/examples/ebin/.gitignore | 0 | ||||
-rw-r--r-- | lib/ssl/examples/src/Makefile | 78 | ||||
-rw-r--r-- | lib/ssl/examples/src/client_server.erl | 85 |
8 files changed, 528 insertions, 0 deletions
diff --git a/lib/ssl/examples/certs/Makefile b/lib/ssl/examples/certs/Makefile new file mode 100644 index 0000000000..121fcc6950 --- /dev/null +++ b/lib/ssl/examples/certs/Makefile @@ -0,0 +1,24 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2003-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +# +# Invoke with GNU make or clearmake -C gnu. +# + +include $(ERL_TOP)/make/run_make.mk diff --git a/lib/ssl/examples/certs/Makefile.in b/lib/ssl/examples/certs/Makefile.in new file mode 100644 index 0000000000..4ea7aaf6dc --- /dev/null +++ b/lib/ssl/examples/certs/Makefile.in @@ -0,0 +1,80 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2003-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +# + +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +include ../../vsn.mk +VSN=$(SSL_VSN) + +RELSYSDIR = $(RELEASE_PATH)/lib/ssl-$(VSN) + +EBIN = ebin +ETC = etc +SRC = src + +OPENSSL_CMD = @OPENSSL_CMD@ + +# We are generating more files than in the following list, but we take +# there existence as successful execution of make rules + +PEMS = cacerts.pem cert.pem key.pem + +PEMFILES = $(PEMS:%=$(ETC)/client/%) $(PEMS:%=$(ETC)/server/%) + +debug opt: $(PEMFILES) + +$(PEMFILES): done + +done: $(EBIN)/make_certs.beam + erl -noinput -pa $(EBIN) -run make_certs all $(OPENSSL_CMD) \ + -s erlang halt + echo >done + +$(EBIN)/make_certs.beam: $(SRC)/make_certs.erl + cd src; erlc -W -o ../$(EBIN) make_certs.erl + +clean: + rm -fr $(EBIN)/* $(SRC)/*~ $(SRC)/*.beam $(ETC) done \ + stderr.txt erl_crash.dump *~ + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/examples/certs + tar cf - Makefile ebin etc rnd src | \ + (cd $(RELSYSDIR)/examples/certs; tar xf -) + chmod -f -R ug+rw $(RELSYSDIR)/examples + +release_docs_spec: + + + + + + + + diff --git a/lib/ssl/examples/certs/ebin/.gitignore b/lib/ssl/examples/certs/ebin/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/ssl/examples/certs/ebin/.gitignore diff --git a/lib/ssl/examples/certs/rnd/RAND b/lib/ssl/examples/certs/rnd/RAND Binary files differnew file mode 100644 index 0000000000..70997bd01f --- /dev/null +++ b/lib/ssl/examples/certs/rnd/RAND diff --git a/lib/ssl/examples/certs/src/make_certs.erl b/lib/ssl/examples/certs/src/make_certs.erl new file mode 100644 index 0000000000..c374836568 --- /dev/null +++ b/lib/ssl/examples/certs/src/make_certs.erl @@ -0,0 +1,261 @@ +%% The purpose of this module is to create example certificates for +%% testing. +%% Run it as: +%% +%% erl -noinput -run make_certs all "/path/to/openssl" -s erlang halt +%% + +-module(make_certs). +-export([all/0, all/1]). + +-record(dn, {commonName, + organizationalUnitName = "Erlang OTP", + organizationName = "Ericsson AB", + localityName = "Stockholm", + countryName = "SE", + emailAddress = "[email protected]"}). + +all() -> + all(["openssl"]). + +all([OpenSSLCmd]) -> + Root = filename:dirname(filename:dirname((code:which(?MODULE)))), + %% io:fwrite("Root : ~s~n", [Root]), + NRoot = filename:join([Root, "etc"]), + file:make_dir(NRoot), + create_rnd(Root, "etc"), % For all requests + rootCA(NRoot, OpenSSLCmd, "erlangCA"), + intermediateCA(NRoot, OpenSSLCmd, "otpCA", "erlangCA"), + endusers(NRoot, OpenSSLCmd, "otpCA", ["client", "server"]), + collect_certs(NRoot, ["erlangCA", "otpCA"], ["client", "server"]), + remove_rnd(Root, "etc"). + +rootCA(Root, OpenSSLCmd, Name) -> + create_ca_dir(Root, Name, ca_cnf(Name)), + DN = #dn{commonName = Name}, + create_self_signed_cert(Root, OpenSSLCmd, Name, req_cnf(DN)), + ok. + +intermediateCA(Root, OpenSSLCmd, CA, ParentCA) -> + CA = "otpCA", + create_ca_dir(Root, CA, ca_cnf(CA)), + CARoot = filename:join([Root, CA]), + DN = #dn{commonName = CA}, + CnfFile = filename:join([CARoot, "req.cnf"]), + file:write_file(CnfFile, req_cnf(DN)), + KeyFile = filename:join([CARoot, "private", "key.pem"]), + ReqFile = filename:join([CARoot, "req.pem"]), + create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile), + CertFile = filename:join([CARoot, "cert.pem"]), + sign_req(Root, OpenSSLCmd, ParentCA, "ca_cert", ReqFile, CertFile). + +endusers(Root, OpenSSLCmd, CA, Users) -> + lists:foreach(fun(User) -> enduser(Root, OpenSSLCmd, CA, User) end, Users). + +enduser(Root, OpenSSLCmd, CA, User) -> + UsrRoot = filename:join([Root, User]), + file:make_dir(UsrRoot), + CnfFile = filename:join([UsrRoot, "req.cnf"]), + DN = #dn{commonName = User}, + file:write_file(CnfFile, req_cnf(DN)), + KeyFile = filename:join([UsrRoot, "key.pem"]), + ReqFile = filename:join([UsrRoot, "req.pem"]), + create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile), + CertFile = filename:join([UsrRoot, "cert.pem"]), + sign_req(Root, OpenSSLCmd, CA, "user_cert", ReqFile, CertFile). + +collect_certs(Root, CAs, Users) -> + Bins = lists:foldr( + fun(CA, Acc) -> + File = filename:join([Root, CA, "cert.pem"]), + {ok, Bin} = file:read_file(File), + [Bin, "\n" | Acc] + end, [], CAs), + lists:foreach( + fun(User) -> + File = filename:join([Root, User, "cacerts.pem"]), + file:write_file(File, Bins) + end, Users). + +create_self_signed_cert(Root, OpenSSLCmd, CAName, Cnf) -> + CARoot = filename:join([Root, CAName]), + CnfFile = filename:join([CARoot, "req.cnf"]), + file:write_file(CnfFile, Cnf), + KeyFile = filename:join([CARoot, "private", "key.pem"]), + CertFile = filename:join([CARoot, "cert.pem"]), + Cmd = [OpenSSLCmd, " req" + " -new" + " -x509" + " -config ", CnfFile, + " -keyout ", KeyFile, + " -out ", CertFile], + Env = [{"ROOTDIR", Root}], + cmd(Cmd, Env). + +create_ca_dir(Root, CAName, Cnf) -> + CARoot = filename:join([Root, CAName]), + file:make_dir(CARoot), + create_dirs(CARoot, ["certs", "crl", "newcerts", "private"]), + create_rnd(Root, filename:join([CAName, "private"])), + create_files(CARoot, [{"serial", "01\n"}, + {"index.txt", ""}, + {"ca.cnf", Cnf}]). + +create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile) -> + Cmd = [OpenSSLCmd, " req" + " -new" + " -config ", CnfFile, + " -keyout ", KeyFile, + " -out ", ReqFile], + Env = [{"ROOTDIR", Root}], + cmd(Cmd, Env). + +sign_req(Root, OpenSSLCmd, CA, CertType, ReqFile, CertFile) -> + CACnfFile = filename:join([Root, CA, "ca.cnf"]), + Cmd = [OpenSSLCmd, " ca" + " -batch" + " -notext" + " -config ", CACnfFile, + " -extensions ", CertType, + " -in ", ReqFile, + " -out ", CertFile], + Env = [{"ROOTDIR", Root}], + cmd(Cmd, Env). + +%% +%% Misc +%% + +create_dirs(Root, Dirs) -> + lists:foreach(fun(Dir) -> + file:make_dir(filename:join([Root, Dir])) end, + Dirs). + +create_files(Root, NameContents) -> + lists:foreach( + fun({Name, Contents}) -> + file:write_file(filename:join([Root, Name]), Contents) end, + NameContents). + +create_rnd(Root, Dir) -> + From = filename:join([Root, "rnd", "RAND"]), + To = filename:join([Root, Dir, "RAND"]), + file:copy(From, To). + +remove_rnd(Root, Dir) -> + File = filename:join([Root, Dir, "RAND"]), + file:delete(File). + +cmd(Cmd, Env) -> + FCmd = lists:flatten(Cmd), + Port = open_port({spawn, FCmd}, [stream, eof, exit_status, + {env, Env}]), + eval_cmd(Port). + +eval_cmd(Port) -> + receive + {Port, {data, _}} -> + eval_cmd(Port); + {Port, eof} -> + ok + end, + receive + {Port, {exit_status, Status}} when Status /= 0 -> + %% io:fwrite("exit status: ~w~n", [Status]), + erlang:halt(Status) + after 0 -> + ok + end. + +%% +%% Contents of configuration files +%% + +req_cnf(DN) -> + ["# Purpose: Configuration for requests (end users and CAs)." + "\n" + "ROOTDIR = $ENV::ROOTDIR\n" + "\n" + + "[req]\n" + "input_password = secret\n" + "output_password = secret\n" + "default_bits = 1024\n" + "RANDFILE = $ROOTDIR/RAND\n" + "encrypt_key = no\n" + "default_md = sha1\n" + "#string_mask = pkix\n" + "x509_extensions = ca_ext\n" + "prompt = no\n" + "distinguished_name= name\n" + "\n" + + "[name]\n" + "commonName = ", DN#dn.commonName, "\n" + "organizationalUnitName = ", DN#dn.organizationalUnitName, "\n" + "organizationName = ", DN#dn.organizationName, "\n" + "localityName = ", DN#dn.localityName, "\n" + "countryName = ", DN#dn.countryName, "\n" + "emailAddress = ", DN#dn.emailAddress, "\n" + "\n" + + "[ca_ext]\n" + "basicConstraints = critical, CA:true\n" + "keyUsage = cRLSign, keyCertSign\n" + "subjectKeyIdentifier = hash\n" + "subjectAltName = email:copy\n"]. + + +ca_cnf(CA) -> + ["# Purpose: Configuration for CAs.\n" + "\n" + "ROOTDIR = $ENV::ROOTDIR\n" + "default_ca = ca\n" + "\n" + + "[ca]\n" + "dir = $ROOTDIR/", CA, "\n" + "certs = $dir/certs\n" + "crl_dir = $dir/crl\n" + "database = $dir/index.txt\n" + "new_certs_dir = $dir/newcerts\n" + "certificate = $dir/cert.pem\n" + "serial = $dir/serial\n" + "crl = $dir/crl.pem\n" + "private_key = $dir/private/key.pem\n" + "RANDFILE = $dir/private/RAND\n" + "\n" + "x509_extensions = user_cert\n" + "default_days = 3600\n" + "default_md = sha1\n" + "preserve = no\n" + "policy = policy_match\n" + "\n" + + "[policy_match]\n" + "commonName = supplied\n" + "organizationalUnitName = optional\n" + "organizationName = match\n" + "countryName = match\n" + "localityName = match\n" + "emailAddress = supplied\n" + "\n" + + "[user_cert]\n" + "basicConstraints = CA:false\n" + "keyUsage = nonRepudiation, digitalSignature, keyEncipherment\n" + "subjectKeyIdentifier = hash\n" + "authorityKeyIdentifier = keyid,issuer:always\n" + "subjectAltName = email:copy\n" + "issuerAltName = issuer:copy\n" + "\n" + + "[ca_cert]\n" + "basicConstraints = critical,CA:true\n" + "keyUsage = cRLSign, keyCertSign\n" + "subjectKeyIdentifier = hash\n" + "authorityKeyIdentifier = keyid:always,issuer:always\n" + "subjectAltName = email:copy\n" + "issuerAltName = issuer:copy\n"]. + + diff --git a/lib/ssl/examples/ebin/.gitignore b/lib/ssl/examples/ebin/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/ssl/examples/ebin/.gitignore diff --git a/lib/ssl/examples/src/Makefile b/lib/ssl/examples/src/Makefile new file mode 100644 index 0000000000..46c0507b3a --- /dev/null +++ b/lib/ssl/examples/src/Makefile @@ -0,0 +1,78 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2003-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +# + +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(SSL_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/ssl-$(VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- +EXTRA_ERLC_FLAGS = +warn_unused_vars +ERL_COMPILE_FLAGS += $(EXTRA_ERLC_FLAGS) + + +MODULES = client_server + +ERL_FILES= $(MODULES:%=%.erl) + +TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug opt: $(TARGET_FILES) + +clean: + rm -fr $(TARGET_FILES) *~ *.beam + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/examples/src + $(INSTALL_DIR) $(RELSYSDIR)/examples/ebin + (cd ..; tar cf - src ebin | (cd $(RELSYSDIR)/examples; tar xf -)) + chmod -f -R ug+w $(RELSYSDIR)/examples + +release_docs_spec: + + + + + + + diff --git a/lib/ssl/examples/src/client_server.erl b/lib/ssl/examples/src/client_server.erl new file mode 100644 index 0000000000..baf5a9185e --- /dev/null +++ b/lib/ssl/examples/src/client_server.erl @@ -0,0 +1,85 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2003-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%%% Purpose: Example of SSL client and server using example certificates. + +-module(client_server). + +-export([start/0, start/1, init_connect/1]). + +start() -> + start([ssl, subject]). + +start(CertOpts) -> + %% Start ssl application + application:start(ssl), + + %% Always seed + ssl:seed("ellynatefttidppohjeh"), + + %% Let the current process be the server that listens and accepts + %% Listen + {ok, LSock} = ssl:listen(0, mk_opts(listen)), + {ok, {_, LPort}} = ssl:sockname(LSock), + io:fwrite("Listen: port = ~w.~n", [LPort]), + + %% Spawn the client process that connects to the server + spawn(?MODULE, init_connect, [{LPort, CertOpts}]), + + %% Accept + {ok, ASock} = ssl:transport_accept(LSock), + ok = ssl:ssl_accept(ASock), + io:fwrite("Accept: accepted.~n"), + {ok, Cert} = ssl:peercert(ASock, CertOpts), + io:fwrite("Accept: peer cert:~n~p~n", [Cert]), + io:fwrite("Accept: sending \"hello\".~n"), + ssl:send(ASock, "hello"), + {error, closed} = ssl:recv(ASock, 0), + io:fwrite("Accept: detected closed.~n"), + ssl:close(ASock), + io:fwrite("Listen: closing and terminating.~n"), + ssl:close(LSock), + application:stop(ssl). + + +%% Client connect +init_connect({LPort, CertOpts}) -> + {ok, Host} = inet:gethostname(), + {ok, CSock} = ssl:connect(Host, LPort, mk_opts(connect)), + io:fwrite("Connect: connected.~n"), + {ok, Cert} = ssl:peercert(CSock, CertOpts), + io:fwrite("Connect: peer cert:~n~p~n", [Cert]), + {ok, Data} = ssl:recv(CSock, 0), + io:fwrite("Connect: got data: ~p~n", [Data]), + io:fwrite("Connect: closing and terminating.~n"), + ssl:close(CSock). + +mk_opts(listen) -> + mk_opts("server"); +mk_opts(connect) -> + mk_opts("client"); +mk_opts(Role) -> + Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]), + [{active, false}, + {verify, 2}, + {depth, 2}, + {cacertfile, filename:join([Dir, Role, "cacerts.pem"])}, + {certfile, filename:join([Dir, Role, "cert.pem"])}, + {keyfile, filename:join([Dir, Role, "key.pem"])}]. + |