diff options
Diffstat (limited to 'lib')
84 files changed, 2286 insertions, 2494 deletions
diff --git a/lib/.gitignore b/lib/.gitignore index a33916b3bf..340baf5269 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -128,6 +128,7 @@ /megaco/src/text/megaco_text_parser_v1.erl /megaco/src/text/megaco_text_parser_v2.erl /megaco/src/text/megaco_text_parser_v3.erl +/megaco/doc/html/mstone1.jpg # mnesia diff --git a/lib/appmon/src/appmon_web.erl b/lib/appmon/src/appmon_web.erl index e8a8422a80..fb7144246c 100644 --- a/lib/appmon/src/appmon_web.erl +++ b/lib/appmon/src/appmon_web.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% Copyright Ericsson AB 2001-2010. 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 @@ -38,12 +38,6 @@ %% webtool -export([configData/0]). - -%% The following directive caters for (significantly) faster native -%% code compilation of one function in this file by the HiPE compiler -%% on register-poor architectures like the x86. --compile([{hipe,[{regalloc,graph_color}]}]). - -behaviour(gen_server). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk index b7e91e42a0..c0393f84fe 100644 --- a/lib/asn1/vsn.mk +++ b/lib/asn1/vsn.mk @@ -1,323 +1,2 @@ #next version number to use is 1.6.15 | 1.7 | 2.0 ASN1_VSN = 1.6.14 - -TICKETS = OTP-8565 \ - OTP-8516 - -TICKETS_1.6.14 = \ - OTP-8565 \ - OTP-8516 - -TICKETS_1.6.13 = \ - OTP-8463 - -TICKETS_1.6.12 = \ - OTP-8256 - -TICKETS_1.6.11 = \ - OTP-8136 \ - OTP-8047 \ - OTP-8046 \ - OTP-8043 \ - OTP-7972 - -TICKETS_1.6.10 = \ - OTP-7954 \ - OTP-7953 - -TICKETS_1.6.10 = \ - OTP-7954 \ - OTP-7953 - -TICKETS_1.6.9 = \ - OTP-7909 \ - OTP-7904 - -TICKETS_1.6.8.1 = \ - OTP-7900 \ - OTP-7910 - -TICKETS_1.6.8 = \ - OTP-7876 - -TICKETS_1.6.7 = \ - OTP-7801 \ - OTP-7806 - -TICKETS_1.6.6 = \ - OTP-7759 \ - OTP-7763 - -TICKETS_1.6.5 = \ - OTP-7734 - -TICKETS_1.6.4 = \ - OTP-7708 - -TICKETS_1.6.3 = \ - OTP-7681 \ - OTP-7678 - -TICKETS_1.6.2 = \ - OTP-7608 - -TICKETS_1.6.1 = \ - OTP-7602 \ - OTP-7533 \ - OTP-7476 \ - OTP-7334 \ - OTP-7332 \ - OTP-7322 \ - OTP-7306 \ - OTP-7299 \ - OTP-7295 \ - OTP-7204 \ - OTP-7174 \ - OTP-7166 - -TICKETS_1.6 = \ - OTP-7407 \ - OTP-7403 \ - OTP-7400 \ - OTP-7375 \ - OTP-7374 \ - OTP-7335 - -TICKETS_1.5.2 = \ - OTP-7263 \ - OTP-7264 \ - OTP-7268 \ - OTP-7269 \ - OTP-7273 - -TICKETS_1.5.1 = \ - OTP-7149 \ - OTP-7151 \ - OTP-7154 \ - OTP-7155 \ - OTP-7169 \ - OTP-7171 \ - OTP-7193 \ - OTP-7199 - -TICKETS_1.5 = \ - OTP-6835 \ - OTP-6882 - -TICKETS_1.4.7 = \ - OTP-6828 - -TICKETS_1.4.6 = \ - OTP-5067 \ - OTP-6763 \ - OTP-6769 \ - OTP-6770 \ - OTP-6786 - -TICKETS_1.4.5 = \ - OTP-6493 \ - OTP-6601 \ - OTP-6695 \ - OTP-6698 \ - OTP-6702 \ - OTP-6707 \ - OTP-6717 - -TICKETS_1.4.4.14 = \ - OTP-6462 \ - OTP-6506 - -TICKETS_1.4.4.13 = \ - OTP-6405 - -TICKETS_1.4.4.12 = \ - OTP-6314 - -TICKETS_1.4.4.11 = \ - OTP-6143 - -TICKETS_1.4.4.10 = \ - OTP-6111 \ - OTP-5932 - -TICKETS_1.4.4.9 = \ - OTP-5783 \ - OTP-5788 \ - OTP-5812 \ - OTP-5831 \ - OPT-5832 - -TICKETS_1.4.4.8 = \ - OTP-5687 \ - OTP-5688 \ - OTP-5689 \ - OTP-5701 \ - OTP-5710 - -TICKETS_1.4.4.7 = \ - OTP-5477 \ - OTP-5509 \ - OTP-5511 \ - OTP-5602 \ - OTP-5616 - -TICKETS_1.4.4.6 = \ - OTP-5457 \ - OTP-5466 - -TICKETS_1.4.4.5 = \ - OTP-5302 \ - OTP-5378 - -TICKETS_1.4.4.4 = \ - OTP-5240 \ - OTP-5243 - -TICKETS_1.4.4.3 = \ - OTP-5103 \ - OTP-5104 - -TICKETS_1.4.4.2 = \ - OTP-5022 - -TICKETS_1.4.4.1 = \ - OTP-4970 - -TICKETS_1.4.4 = \ - OTP-4893 \ - OTP-4894 \ - OTP-4895 \ - OTP-4917 \ - OTP-4918 \ - OTP-4919 \ - OTP-4944 \ - OTP-4953 \ - OTP-4955 \ - OTP-4957 \ - OTP-4965 - -TICKETS_1.4.3.1 = \ - OTP-4866 \ - OTP-4869 \ - OTP-4872 - -TICKETS_1.4.3 = \ - OTP-4832 \ - OTP-4833 \ - OTP-4835 \ - OTP-4856 - -TICKETS_1.4.2.1 = \ - OTP-4773 \ - OTP-4791 \ - OTP-4792 \ - OTP-4797 \ - OTP-4798 \ - OTP-4799 \ - OTP-4809 - -# OTP R9C -TICKETS_1.4.2 = \ - OTP-4693 \ - OTP-4744 - -TICKETS_1.4.1.1 = \ - OTP-4663 \ - OTP-4665 \ - OTP-4666 - -TICKETS_1.4.1 = \ - OTP-4559 \ - OTP-4560 \ - OTP-4590 \ - OTP-4591 \ - OTP-4592 \ - OTP-4631 \ - OTP-4633 - -TICKETS_1.4 = \ - OTP-3304 - -TICKETS_1.3.3.1 = \ - OTP-4353 \ - OTP-4354 \ - OTP-4390 \ - OTP-4395 - -TICKETS_1.3.3 = \ - OTP-4381 \ - OTP-4358 \ - OTP-4355 \ - OTP-4275 \ - OTP-4248 \ - OTP-4247 \ - OTP-4242 \ - OTP-4235 \ - OTP-4234 \ - OTP-4232 \ - OTP-4200 \ - OTP-4161 \ - OTP-4129 - -TICKETS_1.3.2 = \ - OTP-4094 \ - OTP-4103 \ - OTP-3980 \ - OTP-4073 - -TICKETS_1.3.1.1 = \ - OTP-4037 \ - OTP-4057 \ - OTP-4058 - -TICKETS_1.3.1 = \ - OTP-4025 \ - OTP-4026 - -TICKETS_1.3 = \ - OTP-3463 \ - OTP-3659 \ - OTP-3978 \ - OTP-3979 \ - OTP-3981 \ - OTP-3982 \ - OTP-3983 \ - OTP-3985 \ - OTP-3988 \ - OTP-3984 \ - OTP-3994 - -TICKETS_1.2.9.6 = \ - OTP-3830 - -TICKETS_1.2.9.5 = \ - OTP-3713 \ - OTP-3796 \ - OTP-3811 - -TICKETS_1.2.9.3 = \ - OTP-3700 \ - OTP-3701 - -TICKETS_1.2.9.2 = \ - OTP-xxxx - -TICKETS_1.2.9.1 = \ - OTP-xxxx - -TICKETS_1.2.9 = \ - OTP-3569 \ - OTP-3573 - -TICKETS_1.2.8 = \ - OTP-3496 - -TICKETS_1.2.7 = \ - OTP-3395 - -TICKETS_1.2.6 = \ - OTP-3352 - -TICKETS_1.2.5 = \ - OTP-3341 - diff --git a/lib/cosEvent/vsn.mk b/lib/cosEvent/vsn.mk index 9f326b39b6..9c00a17100 100644 --- a/lib/cosEvent/vsn.mk +++ b/lib/cosEvent/vsn.mk @@ -1,15 +1 @@ - COSEVENT_VSN = 2.1.9 - -TICKETS = OTP-8543 - -TICKETS_2.1.8 = OTP-8355 \ - OTP-8409 - -TICKETS_2.1.7 = OTP-8201 - -TICKETS_2.1.6 = OTP-7987 - -TICKETS_2.1.5 = OTP-7837 - -TICKETS_2.1.4 = OTP-7595 diff --git a/lib/cosEventDomain/vsn.mk b/lib/cosEventDomain/vsn.mk index dceee34181..bd21133fe5 100644 --- a/lib/cosEventDomain/vsn.mk +++ b/lib/cosEventDomain/vsn.mk @@ -1,15 +1 @@ - COSEVENTDOMAIN_VSN = 1.1.9 - -TICKETS = OTP-8543 - -TICKETS_1.1.8 = OTP-8353 \ - OTP-8355 - -TICKETS_1.1.7 = OTP-8201 - -TICKETS_1.1.6 = OTP-7987 - -TICKETS_1.1.5 = OTP-7837 - -TICKETS_1.1.4 = OTP-7595 diff --git a/lib/cosFileTransfer/vsn.mk b/lib/cosFileTransfer/vsn.mk index 2700ecb3e3..ef8ee53c5e 100644 --- a/lib/cosFileTransfer/vsn.mk +++ b/lib/cosFileTransfer/vsn.mk @@ -1,16 +1 @@ COSFILETRANSFER_VSN = 1.1.10 - -TICKETS = \ - OTP-8355 \ - OTP-8374 - - -TICKETS_1.1.9 = OTP-8201 - -TICKETS_1.1.8 = OTP-7987 - -TICKETS_1.1.7 = OTP-7837 - -TICKETS_1.1.6 = \ - OTP-7595 \ - OTP-7599
\ No newline at end of file diff --git a/lib/cosNotification/vsn.mk b/lib/cosNotification/vsn.mk index a19facffd5..c03f0ef161 100644 --- a/lib/cosNotification/vsn.mk +++ b/lib/cosNotification/vsn.mk @@ -1,18 +1 @@ COSNOTIFICATION_VSN = 1.1.14 - -TICKETS = OTP-8489 \ - OTP-8543 - -TICKETS_1.1.13 = OTP-8353 \ - OTP-8354 \ - OTP-8355 - -TICKETS_1.1.12 = OTP-8201 - -TICKETS_1.1.11 = OTP-7987 - -TICKETS_1.1.10 = OTP-7837 - -TICKETS_1.1.9 = OTP-7595 - -TICKETS_1.1.8 = OTP-7553 diff --git a/lib/cosProperty/vsn.mk b/lib/cosProperty/vsn.mk index 3d594a8329..ca9a7ca77e 100644 --- a/lib/cosProperty/vsn.mk +++ b/lib/cosProperty/vsn.mk @@ -1,13 +1 @@ COSPROPERTY_VSN = 1.1.12 - -TICKETS = OTP-8543 - -TICKETS_1.1.11 = OTP-8355 - -TICKETS_1.1.10 = OTP-8201 - -TICKETS_1.1.9 = OTP-7987 - -TICKETS_1.1.8 = OTP-7837 - -TICKETS_1.1.7 = OTP-7595 diff --git a/lib/cosTime/vsn.mk b/lib/cosTime/vsn.mk index 9d8057e8db..429613fb61 100644 --- a/lib/cosTime/vsn.mk +++ b/lib/cosTime/vsn.mk @@ -1,13 +1 @@ COSTIME_VSN = 1.1.9 - -TICKETS = OTP-8543 - -TICKETS_1.1.8 = OTP-8355 - -TICKETS_1.1.7 = OTP-8201 - -TICKETS_1.1.6 = OTP-7987 - -TICKETS_1.1.5 = OTP-7837 - -TICKETS_1.1.4 = OTP-7595 diff --git a/lib/cosTransactions/vsn.mk b/lib/cosTransactions/vsn.mk index 34775be7e4..82e46f51dd 100644 --- a/lib/cosTransactions/vsn.mk +++ b/lib/cosTransactions/vsn.mk @@ -1,14 +1 @@ COSTRANSACTIONS_VSN = 1.2.10 - -TICKETS = OTP-8489 \ - OTP-8543 - -TICKETS_1.2.9 = OTP-8355 - -TICKETS_1.2.8 = OTP-8201 - -TICKETS_1.2.7 = OTP-7987 - -TICKETS_1.2.6 = OTP-7837 - -TICKETS_1.2.5 = OTP-7595 diff --git a/lib/docbuilder/vsn.mk b/lib/docbuilder/vsn.mk index 2852ebcc8b..5bb92fd209 100644 --- a/lib/docbuilder/vsn.mk +++ b/lib/docbuilder/vsn.mk @@ -1,14 +1 @@ DOCB_VSN = 0.9.8.7 - -TICKETS = OTP-8343 - -TICKETS_0.9.8.6 = OTP-8201 - -TICKETS_0.9.8.5 = OTP-7851 - -TICKETS_0.9.8.4 = OTP-7236 - -TICKETS_0.9.8.1 = OTP-7236 - - - diff --git a/lib/et/vsn.mk b/lib/et/vsn.mk index b7d65b12a2..c3a42af156 100644 --- a/lib/et/vsn.mk +++ b/lib/et/vsn.mk @@ -17,8 +17,3 @@ # %CopyrightEnd% ET_VSN = 1.4 -TICKETS = OTP-8058 - -TICKETS_1_3_3 = OTP-8201 -TICKETS_1_3_2 = OTP-8078 -TICKETS_1_3_1 = OTP-7830 diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 1f0247a040..6eeeab3610 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -1638,7 +1638,6 @@ type(erlang, system_info, 1, Xs) -> t_non_neg_integer()])])); ['allocator'] -> t_tuple([t_sup([t_atom('undefined'), - t_atom('elib_malloc'), t_atom('glibc')]), t_list(t_integer()), t_list(t_atom()), @@ -1659,9 +1658,8 @@ type(erlang, system_info, 1, Xs) -> t_binary(); ['dist_ctrl'] -> t_list(t_tuple([t_atom(), t_sup([t_pid(), t_port])])); - ['elib_malloc'] -> - t_sup([t_atom('false'), - t_list(t_tuple([t_atom(), t_any()]))]); + %% elib_malloc is intentionally not included, + %% because it scheduled for removal in R15. ['endian'] -> t_endian(); ['fullsweep_after'] -> diff --git a/lib/ic/vsn.mk b/lib/ic/vsn.mk index 4aa2a04b60..074d0b3d39 100644 --- a/lib/ic/vsn.mk +++ b/lib/ic/vsn.mk @@ -1,20 +1 @@ IC_VSN = 4.2.25 - -TICKETS = OTP-8639 - -TICKETS_4.2.24 = OTP-8307 \ - OTP-8353 \ - OTP-8354 \ - OTP-8355 - -TICKETS_4.2.23 = OTP-8201 - -TICKETS_4.2.22 = OTP-8088 - -TICKETS_4.2.21 = OTP-7982 - -TICKETS_4.2.20 = OTP-7837 - -TICKETS_4.2.19 = OTP-7595 - -TICKETS_4.2.18 = OTP-7313 diff --git a/lib/inets/doc/src/http_client.xml b/lib/inets/doc/src/http_client.xml index 510c30eb35..ea8053cafa 100644 --- a/lib/inets/doc/src/http_client.xml +++ b/lib/inets/doc/src/http_client.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2004</year><year>2009</year> + <year>2004</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -56,8 +56,8 @@ <pre> [{inets, [{services, [{httpc, PropertyList}]}]}] </pre> - <p>For valid properties see <seealso - marker="http">http(3)</seealso></p> + <p>For valid properties see + <seealso marker="http">httpc(3)</seealso>. </p> </section> <section> @@ -71,67 +71,66 @@ but not for requests to localhost. This will apply to all subsequent requests</p> <code type="erl"> - 2 > http:set_options([{proxy, {{"www-proxy.mycompany.com", 8000}, + 2 > httpc:set_options([{proxy, {{"www-proxy.mycompany.com", 8000}, ["localhost"]}}]). ok </code> <p>An ordinary synchronous request. </p> <code type="erl"> 3 > {ok, {{Version, 200, ReasonPhrase}, Headers, Body}} = - http:request(get, {"http://www.erlang.org", []}, [], []). + httpc:request(get, {"http://www.erlang.org", []}, [], []). </code> <p>With all default values, as above, a get request can also be written like this.</p> <code type="erl"> 4 > {ok, {{Version, 200, ReasonPhrase}, Headers, Body}} = - http:request("http://www.erlang.org"). + httpc:request("http://www.erlang.org"). </code> <p>An ordinary asynchronous request. The result will be sent to the calling process on the form {http, {ReqestId, Result}}</p> <code type="erl"> 5 > {ok, RequestId} = - http:request(get, {"http://www.erlang.org", []}, [], [{sync, false}]). + httpc:request(get, {"http://www.erlang.org", []}, [], [{sync, false}]). </code> <p>In this case the calling process is the shell, so we receive the result.</p> <code type="erl"> - 6 > receive {http, {RequestId, Result}} -> ok after 500 -> error end. + 6 > receive {http, {RequestId, Result}} -> ok after 500 -> error end. ok </code> <p>Send a request with a specified connection header. </p> <code type="erl"> 7 > {ok, {{NewVersion, 200, NewReasonPhrase}, NewHeaders, NewBody}} = - http:request(get, {"http://www.erlang.org", [{"connection", "close"}]}, + httpc:request(get, {"http://www.erlang.org", [{"connection", "close"}]}, [], []). </code> <p>Start a HTTP client profile. </p> <code><![CDATA[ - 8 > {ok, Pid} = inets:start(httpc, [{profile, foo}]). + 8 > {ok, Pid} = inets:start(httpc, [{profile, foo}]). {ok, <0.45.0>} ]]></code> <p>The new profile has no proxy settings so the connection will be refused</p> <code type="erl"> - 9 > http:request("http://www.erlang.org", foo). - {error,econnrefused} + 9 > httpc:request("http://www.erlang.org", foo). + {error, econnrefused} </code> <p>Stop a HTTP client profile. </p> <code type="erl"> - 10 > inets:stop(httpc, foo). + 10 > inets:stop(httpc, foo). ok </code> <p>Alternatively:</p> <code type="erl"> - 10 > inets:stop(httpc, Pid). + 10 > inets:stop(httpc, Pid). ok </code> - </section> </chapter> diff --git a/lib/inets/doc/src/inets.xml b/lib/inets/doc/src/inets.xml index 81dfe7e944..c367d7fa77 100644 --- a/lib/inets/doc/src/inets.xml +++ b/lib/inets/doc/src/inets.xml @@ -13,12 +13,12 @@ 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. - + </legalnotice> <title>inets</title> @@ -40,13 +40,13 @@ <title>COMMON DATA TYPES </title> <p>Type definitions that are used more than once in this module: </p> - <p><c> service() = ftpc | tfptd | httpc | httpd</c></p> + <p><c> service() = ftpc | tftp | httpc | httpd</c></p> <p><c> property() = atom() </c></p> </section> <funcs> <func> <name>services() -> [{Service, Pid}]</name> - <fsummary>Returns a list of currently running services. </fsummary> + <fsummary>Returns a list of currently running services. </fsummary> <type> <v>Service = service()</v> <v>Pid = pid()</v> @@ -97,7 +97,7 @@ <name>start(Type) -> ok | {error, Reason}</name> <fsummary>Starts the Inets application. </fsummary> <type> - <v>Type = permanent | transient | temporary</v> + <v>Type = permanent | transient | temporary</v> </type> <desc> <p>Starts the Inets application. Default type @@ -115,11 +115,9 @@ </func> <func> <name>start(Service, ServiceConfig) -> {ok, Pid} | {error, Reason}</name> - <name>start(Service, ServiceConfig, How) -> {ok, Pid} | - {error, Reason}</name> + <name>start(Service, ServiceConfig, How) -> {ok, Pid} | {error, Reason}</name> <fsummary>Dynamically starts an inets - service after the inets application has been - started. </fsummary> + service after the inets application has been started. </fsummary> <type> <v>Service = service()</v> <v>ServiceConfig = [{Option, Value}]</v> @@ -153,9 +151,9 @@ <fsummary>Stops a started service of the inets application or takes down a "stand_alone-service" gracefully.</fsummary> <type> - <v>Service = service() | stand_alone</v> + <v>Service = service() | stand_alone</v> <v>Reference = pid() | term() - service specified reference</v> - <v>Reason = term()</v> + <v>Reason = term()</v> </type> <desc> <p>Stops a started service of the inets application or takes @@ -169,7 +167,7 @@ <section> <title>SEE ALSO</title> <p><seealso marker="ftp">ftp(3)</seealso>, - <seealso marker="http">http(3)</seealso>, + <seealso marker="httpc">httpc(3)</seealso>, <seealso marker="httpd">httpd(3)</seealso>, <seealso marker="tftp">tftp(3)</seealso></p> </section> diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index c34b641b7b..8af6613fa2 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 2002-2010. 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% %% %% @@ -605,24 +605,29 @@ handle_info({ssl_error, _, _} = Reason, State) -> %% Internally, to a request handling process, a request timeout is %% seen as a canceled request. handle_info({timeout, RequestId}, - #state{request = #request{id = RequestId} = Request, - canceled = Canceled} = State) -> + #state{request = #request{id = RequestId} = Request, + canceled = Canceled, + profile_name = ProfileName} = State) -> ?hcri("timeout of current request", [{id, RequestId}]), httpc_response:send(Request#request.from, httpc_response:error(Request, timeout)), + httpc_manager:request_done(RequestId, ProfileName), ?hcrv("response (timeout) sent - now terminate", []), {stop, normal, State#state{request = Request#request{from = answer_sent}, canceled = [RequestId | Canceled]}}; -handle_info({timeout, RequestId}, #state{canceled = Canceled} = State) -> +handle_info({timeout, RequestId}, + #state{canceled = Canceled, + profile_name = ProfileName} = State) -> ?hcri("timeout", [{id, RequestId}]), Filter = fun(#request{id = Id, from = From} = Request) when Id =:= RequestId -> ?hcrv("found request", [{id, Id}, {from, From}]), %% Notify the owner - Response = httpc_response:error(Request, timeout), - httpc_response:send(From, Response), + httpc_response:send(From, + httpc_response:error(Request, timeout)), + httpc_manager:request_done(RequestId, ProfileName), ?hcrv("response (timeout) sent", []), [Request#request{from = answer_sent}]; (_) -> diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl index d5d6376369..1e1bde220b 100644 --- a/lib/inets/src/http_client/httpc_manager.erl +++ b/lib/inets/src/http_client/httpc_manager.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 2002-2010. 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% %% %% @@ -66,15 +66,6 @@ state % State of the handler: initiating | started | operational | canceled }). -%% Entries in the handler / request cross-ref table -%% -record(request_info, -%% { -%% id, % Id of the request -%% handler, % Pid of the handler process -%% from, % The From value for the caller -%% mref % Monitor ref for the caller -%% }). - %%==================================================================== %% Internal Application API @@ -577,7 +568,9 @@ handle_info({'EXIT', Pid, Reason}, #state{handler_db = HandlerDb} = State) -> handle_info({'DOWN', _, _, Pid, _}, State) -> %% - %% Check what happens to waiting requests! Chall we not send a reply? + %% Normally this should have been cleaned up already + %% (when receiving {request_done, PequestId}), but + %% just in case there is a glitch, cleanup anyway. %% Pattern = #handler_info{handler = Pid, _ = '_'}, @@ -649,7 +642,16 @@ get_handler_info(Tab) -> Acc end, Handlers2 = lists:foldl(F, [], Handlers1), - Handlers3 = [{Pid, State, httpc_handler:info(Pid)} || + Handlers3 = [{Pid, State, + case (catch httpc_handler:info(Pid)) of + {'EXIT', _} -> + %% Why would this crash? + %% Only if the process has died, but we don't + %% know about it? + []; + Else -> + Else + end} || {Pid, State} <- Handlers2], Handlers3. @@ -666,6 +668,10 @@ handle_started(StarterPid, ReqId, HandlerPid, case ets:lookup(HandlerDb, ReqId) of [#handler_info{state = initiating} = HandlerInfo] -> ?hcri("received started ack for initiating handler", []), + %% As a last resort, make sure we know when it exits, + %% in case it forgets to notify us. + %% We dont need to know the ref id? + erlang:monitor(process, HandlerPid), HandlerInfo2 = HandlerInfo#handler_info{handler = HandlerPid, state = started}, ets:insert(HandlerDb, HandlerInfo2), diff --git a/lib/inets/src/inets_app/inets.erl b/lib/inets/src/inets_app/inets.erl index f1fa5fd997..054468e445 100644 --- a/lib/inets/src/inets_app/inets.erl +++ b/lib/inets/src/inets_app/inets.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 2006-2010. 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% %% %% @@ -57,7 +57,7 @@ start(Type) -> %% Function: start(Service, ServiceConfig [, How]) -> {ok, Pid} | %% {error, Reason} %% -%% Service = - ftpc | tftpd | httpc | httpd +%% Service = - ftpc | tftpd | tftpc | tftp | httpc | httpd %% ServiceConfig = ConfPropList | ConfFile %% ConfPropList = [{Property, Value}] according to service %% ConfFile = Path - when service is httpd @@ -100,7 +100,7 @@ stop() -> %%-------------------------------------------------------------------- %% Function: stop(Service, Pid) -> ok %% -%% Service - ftp | tftpd | http | httpd | stand_alone +%% Service - ftpc | ftp | tftpd | tftpc | tftp | httpc | httpd | stand_alone %% %% Description: Stops a started service of the inets application or takes %% down a stand alone "service" gracefully. @@ -382,7 +382,7 @@ key1search(Key, Vals, Def) -> %% Description: Returns a list of supported services %%------------------------------------------------------------------- service_names() -> - [ftpc, tftpd, httpc, httpd]. + [ftpc, tftp, httpc, httpd]. %%----------------------------------------------------------------- @@ -725,8 +725,8 @@ call_service(Service, Call, Args) -> service_module(tftpd) -> tftp; -service_module(httpc) -> - httpc; +service_module(tftpc) -> + tftp; service_module(ftpc) -> ftp; service_module(Service) -> diff --git a/lib/inets/test/ftp_macosx_x86_test.erl b/lib/inets/test/ftp_macosx_x86_test.erl index c59a992421..5566d4feaa 100644 --- a/lib/inets/test/ftp_macosx_x86_test.erl +++ b/lib/inets/test/ftp_macosx_x86_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% Copyright Ericsson AB 2005-2010. 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 @@ -108,7 +108,7 @@ passive_pwd(X) -> ?LIB_MOD:passive_pwd(X). passive_cd(X) -> ?LIB_MOD:passive_cd(X). passive_lcd(X) -> ?LIB_MOD:passive_lcd(X). passive_ls(X) -> ?LIB_MOD:passive_ls(X). -passive_nlist(X) -> ?LIB_MOD:passive_nlist(X). +passive_nlist(X) -> ?LIB_MOD:passive_nlist([{wildcard_support, false} | X]). passive_rename(X) -> ?LIB_MOD:passive_rename(X). passive_delete(X) -> ?LIB_MOD:passive_delete(X). passive_mkdir(X) -> ?LIB_MOD:passive_mkdir(X). @@ -129,7 +129,7 @@ active_pwd(X) -> ?LIB_MOD:active_pwd(X). active_cd(X) -> ?LIB_MOD:active_cd(X). active_lcd(X) -> ?LIB_MOD:active_lcd(X). active_ls(X) -> ?LIB_MOD:active_ls(X). -active_nlist(X) -> ?LIB_MOD:active_nlist(X). +active_nlist(X) -> ?LIB_MOD:active_nlist([{wildcard_support, false} | X]). active_rename(X) -> ?LIB_MOD:active_rename(X). active_delete(X) -> ?LIB_MOD:active_delete(X). active_mkdir(X) -> ?LIB_MOD:active_mkdir(X). diff --git a/lib/inets/test/ftp_suite_lib.erl b/lib/inets/test/ftp_suite_lib.erl index 5e27bc3a86..c539b7c17c 100644 --- a/lib/inets/test/ftp_suite_lib.erl +++ b/lib/inets/test/ftp_suite_lib.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 2005-2010. 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% %% %% @@ -508,7 +508,8 @@ passive_nlist(suite) -> []; passive_nlist(Config) when is_list(Config) -> Pid = ?config(ftp, Config), - do_nlist(Pid). + WildcardSupport = ?config(wildcard_support, Config), + do_nlist(Pid, WildcardSupport). %%------------------------------------------------------------------------- @@ -768,7 +769,8 @@ active_nlist(suite) -> []; active_nlist(Config) when is_list(Config) -> Pid = ?config(ftp, Config), - do_nlist(Pid). + WildcardSupport = ?config(wildcard_support, Config), + do_nlist(Pid, WildcardSupport). %%------------------------------------------------------------------------- @@ -1242,16 +1244,20 @@ do_ls(Pid) -> {ok, _} = ftp:ls(Pid, "incom*"), ok. -do_nlist(Pid) -> +do_nlist(Pid, WildcardSupport) -> {ok, _} = ftp:nlist(Pid), {ok, _} = ftp:nlist(Pid, "incoming"), %% neither nlist nor ls operates on a directory %% they operate on a pathname, which *can* be a %% directory, but can also be a filename or a group %% of files (including wildcards). - {ok, _} = ftp:nlist(Pid, "incom*"), -%% {error, epath} = ftp:nlist(Pid, ?BAD_DIR), - ok. + case WildcardSupport of + true -> + {ok, _} = ftp:nlist(Pid, "incom*"), + ok; + _ -> + ok + end. do_rename(Pid, Config) -> PrivDir = ?config(priv_dir, Config), diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index b5fd896001..902e440c80 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 2004-2010. 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% %% %% @@ -306,7 +306,8 @@ tickets(suite) -> otp_8106, otp_8056, otp_8352, - otp_8371 + otp_8371, + otp_8739 ]. @@ -2561,7 +2562,78 @@ otp_8371(Config) when is_list(Config) -> ok. +%%------------------------------------------------------------------------- +otp_8739(doc) -> + ["OTP-8739"]; +otp_8739(suite) -> + []; +otp_8739(Config) when is_list(Config) -> + {_DummyServerPid, Port} = otp_8739_dummy_server(), + URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html", + Method = get, + Request = {URL, []}, + HttpOptions = [{connect_timeout, 500}, {timeout, 1}], + Options = [{sync, true}], + case http:request(Method, Request, HttpOptions, Options) of + {error, timeout} -> + %% And now we check the size of the handler db + Info = httpc:info(), + tsp("Info: ~p", [Info]), + {value, {handlers, Handlers}} = + lists:keysearch(handlers, 1, Info), + case Handlers of + [] -> + ok; + _ -> + tsf({unexpected_handlers, Handlers}) + end; + Unexpected -> + tsf({unexpected, Unexpected}) + end. + + +otp_8739_dummy_server() -> + Parent = self(), + Pid = spawn_link(fun() -> otp_8739_dummy_server_init(Parent) end), + receive + {port, Port} -> + {Pid, Port} + end. + +otp_8739_dummy_server_init(Parent) -> + {ok, ListenSocket} = + gen_tcp:listen(0, [binary, inet, {packet, 0}, + {reuseaddr,true}, + {active, false}]), + {ok, Port} = inet:port(ListenSocket), + Parent ! {port, Port}, + otp_8739_dummy_server_main(Parent, ListenSocket). + +otp_8739_dummy_server_main(Parent, ListenSocket) -> + case gen_tcp:accept(ListenSocket) of + {ok, Sock} -> + %% Ignore the request, and simply wait for the socket to close + receive + {tcp_closed, Sock} -> + (catch gen_tcp:close(ListenSocket)), + exit(normal); + {tcp_error, Sock, Reason} -> + tsp("socket error: ~p", [Reason]), + (catch gen_tcp:close(ListenSocket)), + exit(normal) + after 10000 -> + %% Just in case + (catch gen_tcp:close(Sock)), + (catch gen_tcp:close(ListenSocket)), + exit(timeout) + end; + Error -> + exit(Error) + end. + + + %%-------------------------------------------------------------------- %% Internal functions %%-------------------------------------------------------------------- diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk index 57c87e7036..ea6f4c9903 100644 --- a/lib/inets/vsn.mk +++ b/lib/inets/vsn.mk @@ -21,98 +21,3 @@ APPLICATION = inets INETS_VSN = 5.4 PRE_VSN = APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" - -TICKETS = OTP-7907 OTP-8564 OTP-8573 - -TICKETS_5_3_3 = \ - OTP-8609 \ - OTP-8610 \ - OTP-8624 - -TICKETS_5_3_2 = \ - OTP-8542 \ - OTP-8607 - -TICKETS_5_3_1 = \ - OTP-8508 \ - OTP-8509 - -TICKETS_5_3 = \ - OTP-8016 \ - OTP-8056 \ - OTP-8103 \ - OTP-8106 \ - OTP-8312 \ - OTP-8315 \ - OTP-8327 \ - OTP-8349 \ - OTP-8351 \ - OTP-8352 \ - OTP-8359 \ - OTP-8371 - -TICKETS_5_2 = \ - OTP-8204 \ - OTP-8206 \ - OTP-8247 \ - OTP-8248 \ - OTP-8249 \ - OTP-8258 \ - OTP-8280 - -TICKETS_5_1_3 = OTP-8154 - -TICKETS_5_1_2 = OTP-7298 OTP-8101 OTP-8118 - -TICKETS_5_1_1 = OTP-8052 OTP-8069 - -TICKETS_5_1 = OTP-7994 OTP-7998 OTP-8001 OTP-8004 OTP-8005 - -TICKETS_5_0_14 = OTP-7882 OTP-7883 OTP-7888 OTP-7950 OTP-7976 - -TICKETS_5.0.13 = \ - OTP-7723 \ - OTP-7724 \ - OTP-7726 \ - OTP-7463 \ - OTP-7815 \ - OTP-7857 - -# TICKETS_5.0.12 = \ -# OTP-7636 -# -# TICKETS_5.0.11 = \ -# OTP-7574 \ -# OTP-7597 \ -# OTP-7598 \ -# OTP-7605 -# -# TICKETS_5.0.10 = \ -# OTP-7450 \ -# OTP-7454 \ -# OTP-7490 \ -# OTP-7512 -# -# TICKETS_5.0.9 = \ -# OTP-7257 \ -# OTP-7323 \ -# OTP-7341 -# -# TICKETS_5.0.8 = \ -# OTP-7315 \ -# OTP-7321 -# -# TICKETS_5.0.7 = \ -# OTP-7304 -# -# TICKETS_5.0.6 = \ -# OTP-7266 -# -# TICKETS_5.0.5 = \ -# OTP-7220 \ -# OTP-7221 -# -# TICKETS_5.0.4 = \ -# OTP-7173 -# - diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml index 4e65bf46f8..9a62b45d63 100644 --- a/lib/kernel/doc/src/erl_ddll.xml +++ b/lib/kernel/doc/src/erl_ddll.xml @@ -177,7 +177,7 @@ <name>demonitor(MonitorRef) -> ok</name> <fsummary>Remove a monitor for a driver</fsummary> <type> - <v>MonitorRef = ref()</v> + <v>MonitorRef = reference()</v> </type> <desc> <p>Removes a driver monitor in much the same way as @@ -185,7 +185,7 @@ monitors. See <seealso marker="#monitor/2">monitor/2</seealso>, <seealso marker="#try_load/3">try_load/3</seealso> and <seealso marker="#try_unload/2">try_unload/2</seealso> for details about how to create driver monitors.</p> <p>The function throws a <c>badarg</c> exception if the - parameter is not a ref(). </p> + parameter is not a reference(). </p> </desc> </func> <func> @@ -400,7 +400,7 @@ <v>Item = {Name, When}</v> <v>Name = atom() | string()</v> <v>When = loaded | unloaded | unloaded_only</v> - <v>MonitorRef = ref()</v> + <v>MonitorRef = reference()</v> </type> <desc> <p>This function creates a driver monitor and works in many @@ -449,7 +449,7 @@ eventually lead to one of the following messages being sent:</p> <taglist> - <tag><em>{'UP', ref(), driver, Name, loaded}</em></tag> + <tag><em>{'UP', reference(), driver, Name, loaded}</em></tag> <item> <p>This message is sent, either immediately if the driver is already loaded and no reloading is @@ -459,7 +459,7 @@ expected to know if reloading is demanded prior to creating a monitor for loading.</p> </item> - <tag><em>{'UP', ref(), driver, Name, permanent}</em></tag> + <tag><em>{'UP', reference(), driver, Name, permanent}</em></tag> <item> <p>This message will be sent if reloading was expected, but the (old) driver made itself @@ -467,7 +467,7 @@ sent if the driver was permanent or statically linked in when trying to create the monitor.</p> </item> - <tag><em>{'DOWN', ref(), driver, Name, load_cancelled}</em></tag> + <tag><em>{'DOWN', reference(), driver, Name, load_cancelled}</em></tag> <item> <p>This message will arrive if reloading was underway, but the <seealso marker="#users">user</seealso> having requested @@ -476,7 +476,7 @@ (or <c>unload/1</c>/<c>unload_driver/1</c>) again before it was reloaded.</p> </item> - <tag><em>{'DOWN', ref(), driver, Name, {load_failure, Failure}}</em></tag> + <tag><em>{'DOWN', reference(), driver, Name, {load_failure, Failure}}</em></tag> <item> <p>This message will arrive if reloading was underway but the loading for some reason @@ -500,7 +500,7 @@ <p>A driver monitor for unload will eventually result in one of the following messages being sent:</p> <taglist> - <tag><em>{'DOWN', ref(), driver, Name, unloaded}</em></tag> + <tag><em>{'DOWN', reference(), driver, Name, unloaded}</em></tag> <item> <p>The driver instance monitored is now unloaded. As the unload might have been due to a @@ -508,7 +508,7 @@ again have been loaded when this message arrives.</p> </item> - <tag><em>{'UP', ref(), driver, Name, unload_cancelled}</em></tag> + <tag><em>{'UP', reference(), driver, Name, unload_cancelled}</em></tag> <item> <p>This message will be sent if unloading was expected, but while the driver was waiting for @@ -525,7 +525,7 @@ similar to an <c>unloaded</c> monitor, but does never result in this message.</p> </item> - <tag><em>{'UP', ref(), driver, Name, permanent}</em></tag> + <tag><em>{'UP', reference(), driver, Name, permanent}</em></tag> <item> <p>This message will be sent if unloading was expected, but the driver made itself @@ -539,7 +539,7 @@ <item> <p>A monitor created as <c>unloaded_only</c> behaves exactly as one created as <c>unloaded</c> with the - exception that the <c>{'UP', ref(), driver, Name, unload_cancelled}</c> message will never be + exception that the <c>{'UP', reference(), driver, Name, unload_cancelled}</c> message will never be sent, but the monitor instead persists until the driver <em>really</em> gets unloaded.</p> </item> @@ -626,7 +626,7 @@ <v>ReloadOption = pending_driver | pending</v> <v>Status = loaded | already_loaded | PendingStatus </v> <v>PendingStatus = pending_driver | pending_process</v> - <v>Ref = ref()</v> + <v>Ref = reference()</v> <v>ErrorDesc = ErrorAtom | OpaqueError</v> <v>ErrorAtom = linked_in_driver | inconsistent | permanent | not_loaded_by_this_process | not_loaded | pending_reload | pending_process</v> </type> @@ -650,7 +650,7 @@ registered and a corresponding <c>try_unload</c> is expected sometime in the future.</p> </item> - <tag><em>{ok, pending_driver}</em>or <em>{ok, pending_driver, ref()}</em></tag> + <tag><em>{ok, pending_driver}</em>or <em>{ok, pending_driver, reference()}</em></tag> <item> <p>The load request is registered, but the loading is delayed due to the fact that an earlier instance of the @@ -665,7 +665,7 @@ set. In other words, this return value will always need to be handled!</p> </item> - <tag><em>{ok, pending_process}</em>or <em>{ok, pending_process, ref()}</em></tag> + <tag><em>{ok, pending_process}</em>or <em>{ok, pending_process, reference()}</em></tag> <item> <p>The load request is registered, but the loading is delayed due to the fact that an earlier instance of the @@ -683,7 +683,7 @@ about when the driver is <em>actually</em> loaded. This can be achieved by using the <c>{monitor, PendingOption}</c> option.</p> <p>When monitoring is requested, and a corresponding <c>{ok, pending_driver}</c> or <c>{ok, pending_process}</c> would be - returned, the function will instead return a tuple <c>{ok, PendingStatus, ref()}</c> and the process will, at a later + returned, the function will instead return a tuple <c>{ok, PendingStatus, reference()}</c> and the process will, at a later time when the driver actually gets loaded, get a monitor message. The monitor message one can expect is described in the <seealso marker="#monitor/2">monitor/2</seealso> @@ -760,7 +760,7 @@ <p>A <c>MonitorOption</c> tells <c>try_load/3</c> to trigger a driver monitor under certain conditions. When the monitor is triggered, the - function will return a three-tuple <c>{ok, PendingStatus, ref()}</c>, where the <c>ref()</c> is + function will return a three-tuple <c>{ok, PendingStatus, reference()}</c>, where the <c>reference()</c> is the monitor ref for the driver monitor.</p> <p>Only one <c>MonitorOption</c> can be specified and it is either the atom <c>pending</c>, which means @@ -891,7 +891,7 @@ <v>MonitorOption = pending_driver | pending</v> <v>Status = unloaded | PendingStatus </v> <v>PendingStatus = pending_driver | pending_process</v> - <v>Ref = ref()</v> + <v>Ref = reference()</v> <v>ErrorAtom = linked_in_driver | not_loaded | not_loaded_by_this_process | permanent</v> </type> <desc> @@ -943,7 +943,7 @@ ports using it and there are no more <seealso marker="#users">users</seealso> requiring it to be loaded.</p> </item> - <tag><em>{ok, pending_driver}</em>or <em>{ok, pending_driver, ref()}</em></tag> + <tag><em>{ok, pending_driver}</em>or <em>{ok, pending_driver, reference()}</em></tag> <item> <p>This return value indicates that this call removed the last <seealso marker="#users">user</seealso> from the @@ -957,7 +957,7 @@ in that case, however transient. Monitors are as always useful to detect when the driver is really unloaded.</p> </item> - <tag><em>{ok, pending_process}</em>or <em>{ok, pending_process, ref()}</em></tag> + <tag><em>{ok, pending_process}</em>or <em>{ok, pending_process, reference()}</em></tag> <item> <p>The unload request is registered, but there are still other <seealso marker="#users">users</seealso> holding diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk index efb46253aa..f28c89abbe 100644 --- a/lib/megaco/vsn.mk +++ b/lib/megaco/vsn.mk @@ -21,131 +21,3 @@ APPLICATION = megaco MEGACO_VSN = 3.14.1.1 PRE_VSN = APP_VSN = "$(APPLICATION)-$(MEGACO_VSN)$(PRE_VSN)" - -TICKETS = OTP-8696 - -TICKETS_3_14_1 = OTP-8529 OTP-8561 OTP-8627 OTP-8634 - -TICKETS_3_14 = OTP-8317 OTP-8323 OTP-8328 OTP-8362 OTP-8403 - -TICKETS_3_13 = OTP-8205 OTP-8239 OTP-8249 - -TICKETS_3_12 = OTP-8183 OTP-8212 - -TICKETS_3_11_3 = OTP-8164 OTP-8167 OTP-8191 - -TICKETS_3_11_2 = OTP-8123 - -TICKETS_3_11_1 = OTP-8081 OTP-8114 - -TICKETS_3_11 = OTP-7302 OTP-7995 - -TICKETS_3_10_1 = OTP-7926 OTP-7936 - -TICKETS_3_10_0_1 = OTP-7851 - -TICKETS_3_10 = OTP-7713 OTP-7743 - -TICKETS_3_9_4 = OTP-7728 OTP-7733 - -TICKETS_3_9_3 = OTP-7700 - -TICKETS_3_9_2 = OTP-7671 OTP-7672 - -TICKETS_3_9_1_1 = OTP-7614 - -TICKETS_3_9_1 = OTP-7572 OTP-7573 OTP-7576 - -TICKETS_3_9 = OTP-7431 - -TICKETS_3_8_2 = OTP-7534 - -TICKETS_3_8_1 = OTP-7398 OTP-7417 OTP-7444 OTP-7449 OTP-7455 OTP-7457 OTP-7459 - -TICKETS_3_8 = OTP-7192 OTP-7228 OTP-7259 - -TICKETS_3_7_5 = OTP-7286 OTP-7303 - -TICKETS_3_7_4 = OTP-7249 OTP-7251 - -TICKETS_3_7_3 = OTP-7168 OTP-7180 OTP-7189 OTP-7216 - -TICKETS_3_7_2 = OTP-6972 OTP-7138 - -TICKETS_3_7_1 = OTP-6919 OTP-6971 OTP-6992 OTP-6999 OTP-7000 OTP-7005 OTP-7124 - -TICKETS_3_7 = OTP-5979 OTP-6753 OTP-6804 OTP-6865 OTP-6919 OTP-6976 - -TICKETS_3_6_2 = OTP-6921 - -TICKETS_3_6_1 = OTP-6803 - -TICKETS_3_6_0_1 = OTP-6704 - -TICKETS_3_6 = OTP-6185 OTP-6578 OTP-6441 OTP-6442 OTP-6544 OTP-6605 OTP-6609 - -TICKETS_3_5_3 = OTP-6520 OTP-6549 - -TICKETS_3_5_2 = OTP-6404 OTP-6422 OTP-6490 OTP-6503 - -TICKETS_3_5_1 = OTP-6275 OTP-6276 - -TICKETS_3_5 = OTP-6223 OTP-6253 OTP-6256 - -TICKETS_3_4_4 = OTP-6181 OTP-6182 OTP-6217 OTP-6219 - -TICKETS_3_4_3 = OTP-6170 OTP-6171 OTP-6172 - -TICKETS_3_4_2 = OTP-6148 - -TICKETS_3_4_1 = OTP-6113 - -TICKETS_3_4 = \ - OTP-5769 \ - OTP-5980 \ - OTP-6009 \ - OTP-6025 \ - OTP-6028 \ - OTP-6030 \ - OTP-6048 \ - OTP-6051 \ - OTP-6052 \ - OTP-6055 \ - OTP-6089 \ - OTP-6090 - -TICKETS_3_3_5 = OTP-6108 - -TICKETS_3_3_4 = OTP-6076 - -TICKETS_3_3_3 = OTP-6046 - -TICKETS_3_3_2 = OTP-6017 OTP-6022 - -TICKETS_3_3_1 = OTP-5993 - -TICKETS_3_3 = OTP-5965 OTP-5973 - -TICKETS_3_2_7 = OTP-5948 OTP-5952 OTP-5953 - -TICKETS_3_2_6 = OTP-5918 OTP-5919 OTP-5920 - -TICKETS_3_2_5 = OTP-5887 - -TICKETS_3_2_4 = OTP-5867 OTP-5879 OTP-5880 OTP-5881 OTP-5882 OTP-5885 OTP-5886 - -TICKETS_3_2_3 = OTP-5826 OTP-5830 OTP-5833 OTP-5836 OTP-5839 - -TICKETS_3_2_2 = OTP-5799 OTP-5803 OTP-5804 OTP-5805 OTP-5816 - -TICKETS_3_2_1 = OTP-5725 OTP-5793 - -TICKETS_3_2 = OTP-5717 OTP-5750 - -TICKETS_3_1 = OTP-5542 OTP-5597 OTP-5600 OTP-5601 OTP-5619 OTP-5664 - -TICKETS_3_0_1 = \ - OTP-5401 \ - OTP-5446 \ - OTP-5447 - diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk index 2780b737b6..ab2bb73c33 100644 --- a/lib/mnesia/vsn.mk +++ b/lib/mnesia/vsn.mk @@ -1,17 +1 @@ - MNESIA_VSN = 4.4.14 - -TICKETS = OTP-8519 -#TICKETS_4.4.13 = OTP-8402 OTP-8406 -#TICKETS_4.4.12 = OTP-8250 -#TICKETS_4.4.11 = OTP-8074 -#TICKETS_4.4.10 = OTP-7928 OTP-7968 OTP-8002 -#TICKETS_4.4.9 = OTP-7911 -#TICKETS_4.4.8 = OTP-7753 OTP-7835 -#TICKETS_4.4.7 = OTP-7524 OTP-7625 -#TICKETS_4.4.6 = OTP-7585 -#TICKETS_4.4.5 = OTP-7466 -#TICKETS_4.4.4 = OTP-7419 -#TICKETS_4.4.3 = OTP-7340 OTP-7378 OTP-7383 -#TICKETS_4.4.2 = OTP-7205 OTP-7208 -#TICKETS_4.4.1 = OTP-7170 diff --git a/lib/odbc/vsn.mk b/lib/odbc/vsn.mk index d813466437..fac3f06d4b 100644 --- a/lib/odbc/vsn.mk +++ b/lib/odbc/vsn.mk @@ -1,23 +1 @@ ODBC_VSN = 2.10.8 - -TICKETS = OTP-7452 OTP-8511 - -TICKETS_2.10.6 = \ - OTP-8250 \ - OTP-8291 - -TICKETS_2.10.5 = \ - OTP-7978 - -TICKETS_2.10.4 = \ - OTP-7720 \ - OTP-7721 - -TICKETS_2.10.3 = \ - OTP-7418 -TICKETS_2.10.2 = \ - OTP-7297 -TICKETS_2.10.1 = \ - OTP-7019 \ - OTP-7294 \ - OTP-7307 diff --git a/lib/orber/vsn.mk b/lib/orber/vsn.mk index ec349ee189..cf80e27a61 100644 --- a/lib/orber/vsn.mk +++ b/lib/orber/vsn.mk @@ -1,21 +1 @@ - ORBER_VSN = 3.6.16 - -TICKETS = OTP-8489 \ - OTP-8543 - -TICKETS_3.6.15 = OTP-8353 \ - OTP-8354 \ - OTP-8374 \ - OTP-8409 \ - OTP-8448 - -TICKETS_3.6.14 = OTP-8201 - -TICKETS_3.6.13 = OTP-7987 - -TICKETS_3.6.12 = OTP-7906 - -TICKETS_3.6.11 = OTP-7837 - -TICKETS_3.6.10 = OTP-7595 diff --git a/lib/parsetools/include/yeccpre.hrl b/lib/parsetools/include/yeccpre.hrl index 33a103d95f..39dea0552d 100644 --- a/lib/parsetools/include/yeccpre.hrl +++ b/lib/parsetools/include/yeccpre.hrl @@ -26,8 +26,8 @@ parse(Tokens) -> yeccpars0(Tokens, {no_func, no_line}, 0, [], []). --spec parse_and_scan({function() | {atom(), atom()}, [_]} | {atom(), atom(), [_]}) -> - yecc_ret(). +-spec parse_and_scan({function() | {atom(), atom()}, [_]} + | {atom(), atom(), [_]}) -> yecc_ret(). parse_and_scan({F, A}) -> % Fun or {M, F} yeccpars0([], {{F, A}, no_line}, 0, [], []); parse_and_scan({M, F, A}) -> @@ -44,7 +44,7 @@ format_error(Message) -> %% To be used in grammar files to throw an error message to the parser %% toplevel. Doesn't have to be exported! --compile({nowarn_unused_function,{return_error,2}}). +-compile({nowarn_unused_function, return_error/2}). -spec return_error(integer(), any()) -> no_return(). return_error(Line, Message) -> throw({error, {Line, ?MODULE, Message}}). @@ -57,10 +57,7 @@ yeccpars0(Tokens, Tzr, State, States, Vstack) -> error: Error -> Stacktrace = erlang:get_stacktrace(), try yecc_error_type(Error, Stacktrace) of - {syntax_error, Token} -> - yeccerror(Token); - {missing_in_goto_table=Tag, Symbol, State} -> - Desc = {Symbol, State, Tag}, + Desc -> erlang:raise(error, {yecc_bug, ?CODE_VERSION, Desc}, Stacktrace) catch _:_ -> erlang:raise(error, Error, Stacktrace) @@ -70,13 +67,15 @@ yeccpars0(Tokens, Tzr, State, States, Vstack) -> Error end. -yecc_error_type(function_clause, [{?MODULE,F,[State,_,_,_,Token,_,_]} | _]) -> +yecc_error_type(function_clause, [{?MODULE,F,ArityOrArgs} | _]) -> case atom_to_list(F) of - "yeccpars2" ++ _ -> - {syntax_error, Token}; "yeccgoto_" ++ SymbolL -> {ok,[{atom,_,Symbol}],_} = erl_scan:string(SymbolL), - {missing_in_goto_table, Symbol, State} + State = case ArityOrArgs of + [S,_,_,_,_,_,_] -> S; + _ -> state_is_unknown + end, + {Symbol, State, missing_in_goto_table} end. yeccpars1([Token | Tokens], Tzr, State, States, Vstack) -> @@ -141,11 +140,13 @@ yecctoken_end_location(Token) -> yecctoken_location(Token) end. +-compile({nowarn_unused_function, yeccerror/1}). yeccerror(Token) -> Text = yecctoken_to_string(Token), Location = yecctoken_location(Token), {error, {Location, ?MODULE, ["syntax error before: ", Text]}}. +-compile({nowarn_unused_function, yecctoken_to_string/1}). yecctoken_to_string(Token) -> case catch erl_scan:token_info(Token, text) of {text, Txt} -> Txt; @@ -158,6 +159,7 @@ yecctoken_location(Token) -> _ -> element(2, Token) end. +-compile({nowarn_unused_function, yecctoken2string/1}). yecctoken2string({atom, _, A}) -> io_lib:write(A); yecctoken2string({integer,_,N}) -> io_lib:write(N); yecctoken2string({float,_,F}) -> io_lib:write(F); diff --git a/lib/parsetools/src/yecc.erl b/lib/parsetools/src/yecc.erl index c4a47d008f..4119e2631b 100644 --- a/lib/parsetools/src/yecc.erl +++ b/lib/parsetools/src/yecc.erl @@ -1875,8 +1875,12 @@ format_conflict({Symbol, N, Reduce, Confl}) -> %% - "__Stack" has been substituted for "Stack"; %% - several states can share yeccpars2_S_cont(), which reduces code size; %% - instead if calling lists:nthtail() matching code is emitted. +%% +%% "1.4", parsetools-2.0.4: +%% - yeccerror() is called when a syntax error is found (as in version 1.1). +%% - the include file yeccpre.hrl has been changed. --define(CODE_VERSION, "1.3"). +-define(CODE_VERSION, "1.4"). -define(YECC_BUG(M, A), iolist_to_binary([" erlang:error({yecc_bug,\"",?CODE_VERSION,"\",", io_lib:fwrite(M, A), "}).\n\n"])). @@ -2106,13 +2110,11 @@ output_call_to_includefile(NewState, St) -> fwrite(St, <<" yeccpars1(S, ~w, Ss, Stack, T, Ts, Tzr)">>, [NewState]). -output_state_actions_fini(State, #yecc{includefile_version = {1,1}}=St0) -> - %% Backward compatibility. +output_state_actions_fini(State, St0) -> + %% Backward compatible. St10 = delim(St0, false), St = fwrite(St10, <<"yeccpars2_~w(_, _, _, _, T, _, _) ->\n">>, [State]), - fwrite(St, <<" yeccerror(T).\n\n">>, []); -output_state_actions_fini(_State, St) -> - fwrite(St, <<".\n\n">>, []). + fwrite(St, <<" yeccerror(T).\n\n">>, []). output_reduce(St0, State, Terminal0, #reduce{rule_nmbr = RuleNmbr, @@ -2416,7 +2418,7 @@ include1(Line, Inport, Outport, Nmbr_of_lines) -> include1(io:get_line(Inport, ''), Inport, Outport, Nmbr_of_lines + Incr). includefile_version([]) -> - {1,2}; + {1,4}; includefile_version(Includefile) -> case epp:open(Includefile, []) of {ok, Epp} -> @@ -2432,7 +2434,7 @@ includefile_version(Includefile) -> parse_file(Epp) -> case epp:parse_erl_form(Epp) of {ok, {function,_Line,yeccpars1,7,_Clauses}} -> - {1,2}; + {1,4}; {eof,_Line} -> {1,1}; _Form -> diff --git a/lib/parsetools/src/yeccparser.erl b/lib/parsetools/src/yeccparser.erl index 415547b4ce..63127802ee 100644 --- a/lib/parsetools/src/yeccparser.erl +++ b/lib/parsetools/src/yeccparser.erl @@ -38,16 +38,16 @@ line_of(Token) -> -type yecc_ret() :: {'error', _} | {'ok', _}. --spec parse(_) -> yecc_ret(). +-spec parse(Tokens :: list()) -> yecc_ret(). parse(Tokens) -> - yeccpars0(Tokens, false). + yeccpars0(Tokens, {no_func, no_line}, 0, [], []). --spec parse_and_scan({function() | {atom(), atom()}, [_]} | {atom(), atom(), [_]}) -> - yecc_ret(). +-spec parse_and_scan({function() | {atom(), atom()}, [_]} + | {atom(), atom(), [_]}) -> yecc_ret(). parse_and_scan({F, A}) -> % Fun or {M, F} - yeccpars0([], {F, A}); + yeccpars0([], {{F, A}, no_line}, 0, [], []); parse_and_scan({M, F, A}) -> - yeccpars0([], {{M, F}, A}). + yeccpars0([], {{{M, F}, A}, no_line}, 0, [], []). -spec format_error(any()) -> [char() | list()]. format_error(Message) -> @@ -60,54 +60,58 @@ format_error(Message) -> %% To be used in grammar files to throw an error message to the parser %% toplevel. Doesn't have to be exported! --compile({nowarn_unused_function,{return_error,2}}). +-compile({nowarn_unused_function, return_error/2}). -spec return_error(integer(), any()) -> no_return(). return_error(Line, Message) -> throw({error, {Line, ?MODULE, Message}}). --define(CODE_VERSION, "1.3"). +-define(CODE_VERSION, "1.4"). -yeccpars0(Tokens, MFA) -> - try yeccpars1(Tokens, MFA, 0, [], []) +yeccpars0(Tokens, Tzr, State, States, Vstack) -> + try yeccpars1(Tokens, Tzr, State, States, Vstack) catch error: Error -> Stacktrace = erlang:get_stacktrace(), try yecc_error_type(Error, Stacktrace) of - {syntax_error, Token} -> - yeccerror(Token); - {missing_in_goto_table=Tag, Symbol, State} -> - Desc = {Symbol, State, Tag}, + Desc -> erlang:raise(error, {yecc_bug, ?CODE_VERSION, Desc}, - Stacktrace) + Stacktrace) catch _:_ -> erlang:raise(error, Error, Stacktrace) end; - throw: {error, {_Line, ?MODULE, _M}} = Error -> - Error % probably from return_error/2 + %% Probably thrown from return_error/2: + throw: {error, {_Line, ?MODULE, _M}} = Error -> + Error end. -yecc_error_type(function_clause, [{?MODULE,F,[State,_,_,_,Token,_,_]} | _]) -> +yecc_error_type(function_clause, [{?MODULE,F,ArityOrArgs} | _]) -> case atom_to_list(F) of - "yeccpars2" ++ _ -> - {syntax_error, Token}; "yeccgoto_" ++ SymbolL -> {ok,[{atom,_,Symbol}],_} = erl_scan:string(SymbolL), - {missing_in_goto_table, Symbol, State} + State = case ArityOrArgs of + [S,_,_,_,_,_,_] -> S; + _ -> state_is_unknown + end, + {Symbol, State, missing_in_goto_table} end. -yeccpars1([Token | Tokens], Tokenizer, State, States, Vstack) -> - yeccpars2(State, element(1, Token), States, Vstack, Token, Tokens, - Tokenizer); -yeccpars1([], {F, A}, State, States, Vstack) -> +yeccpars1([Token | Tokens], Tzr, State, States, Vstack) -> + yeccpars2(State, element(1, Token), States, Vstack, Token, Tokens, Tzr); +yeccpars1([], {{F, A},_Line}, State, States, Vstack) -> case apply(F, A) of - {ok, Tokens, _Endline} -> - yeccpars1(Tokens, {F, A}, State, States, Vstack); - {eof, _Endline} -> - yeccpars1([], false, State, States, Vstack); + {ok, Tokens, Endline} -> + yeccpars1(Tokens, {{F, A}, Endline}, State, States, Vstack); + {eof, Endline} -> + yeccpars1([], {no_func, Endline}, State, States, Vstack); {error, Descriptor, _Endline} -> {error, Descriptor} end; -yeccpars1([], false, State, States, Vstack) -> - yeccpars2(State, '$end', States, Vstack, {'$end', 999999}, [], false). +yeccpars1([], {no_func, no_line}, State, States, Vstack) -> + Line = 999999, + yeccpars2(State, '$end', States, Vstack, yecc_end(Line), [], + {no_func, Line}); +yeccpars1([], {no_func, Endline}, State, States, Vstack) -> + yeccpars2(State, '$end', States, Vstack, yecc_end(Endline), [], + {no_func, Endline}). %% yeccpars1/7 is called from generated code. %% @@ -115,48 +119,73 @@ yeccpars1([], false, State, States, Vstack) -> %% yeccpars1/7 can be found by parsing the file without following %% include directives. yecc will otherwise assume that an old %% yeccpre.hrl is included (one which defines yeccpars1/5). -yeccpars1(State1, State, States, Vstack, Stack1, [Token | Tokens], - Tokenizer) -> +yeccpars1(State1, State, States, Vstack, Token0, [Token | Tokens], Tzr) -> yeccpars2(State, element(1, Token), [State1 | States], - [Stack1 | Vstack], Token, Tokens, Tokenizer); -yeccpars1(State1, State, States, Vstack, Stack1, [], {F, A}) -> - case apply(F, A) of - {ok, Tokens, _Endline} -> - yeccpars1(State1, State, States, Vstack, Stack1, Tokens, {F, A}); - {eof, _Endline} -> - yeccpars1(State1, State, States, Vstack, Stack1, [], false); - {error, Descriptor, _Endline} -> - {error, Descriptor} - end; -yeccpars1(State1, State, States, Vstack, Stack1, [], false) -> - yeccpars2(State, '$end', [State1 | States], [Stack1 | Vstack], - {'$end', 999999}, [], false). + [Token0 | Vstack], Token, Tokens, Tzr); +yeccpars1(State1, State, States, Vstack, Token0, [], {{_F,_A}, _Line}=Tzr) -> + yeccpars1([], Tzr, State, [State1 | States], [Token0 | Vstack]); +yeccpars1(State1, State, States, Vstack, Token0, [], {no_func, no_line}) -> + Line = yecctoken_end_location(Token0), + yeccpars2(State, '$end', [State1 | States], [Token0 | Vstack], + yecc_end(Line), [], {no_func, Line}); +yeccpars1(State1, State, States, Vstack, Token0, [], {no_func, Line}) -> + yeccpars2(State, '$end', [State1 | States], [Token0 | Vstack], + yecc_end(Line), [], {no_func, Line}). + +%% For internal use only. +yecc_end({Line,_Column}) -> + {'$end', Line}; +yecc_end(Line) -> + {'$end', Line}. + +yecctoken_end_location(Token) -> + try + {text, Str} = erl_scan:token_info(Token, text), + {line, Line} = erl_scan:token_info(Token, line), + Parts = re:split(Str, "\n"), + Dline = length(Parts) - 1, + Yline = Line + Dline, + case erl_scan:token_info(Token, column) of + {column, Column} -> + Col = byte_size(lists:last(Parts)), + {Yline, Col + if Dline =:= 0 -> Column; true -> 1 end}; + undefined -> + Yline + end + catch _:_ -> + yecctoken_location(Token) + end. -% For internal use only. yeccerror(Token) -> - Text = case catch erl_scan:token_info(Token, text) of - {text, Txt} -> Txt; - _ -> yecctoken2string(Token) - end, - Location = case catch erl_scan:token_info(Token, location) of - {location, Loc} -> Loc; - _ -> element(2, Token) - end, + Text = yecctoken_to_string(Token), + Location = yecctoken_location(Token), {error, {Location, ?MODULE, ["syntax error before: ", Text]}}. +yecctoken_to_string(Token) -> + case catch erl_scan:token_info(Token, text) of + {text, Txt} -> Txt; + _ -> yecctoken2string(Token) + end. + +yecctoken_location(Token) -> + case catch erl_scan:token_info(Token, location) of + {location, Loc} -> Loc; + _ -> element(2, Token) + end. + yecctoken2string({atom, _, A}) -> io_lib:write(A); yecctoken2string({integer,_,N}) -> io_lib:write(N); yecctoken2string({float,_,F}) -> io_lib:write(F); yecctoken2string({char,_,C}) -> io_lib:write_char(C); yecctoken2string({var,_,V}) -> io_lib:format("~s", [V]); yecctoken2string({string,_,S}) -> io_lib:write_unicode_string(S); -yecctoken2string({reserved_symbol, _, A}) -> io_lib:format("~w", [A]); -yecctoken2string({_Cat, _, Val}) -> io_lib:format("~w", [Val]); +yecctoken2string({reserved_symbol, _, A}) -> io_lib:write(A); +yecctoken2string({_Cat, _, Val}) -> io_lib:write(Val); yecctoken2string({dot, _}) -> "'.'"; yecctoken2string({'$end', _}) -> []; yecctoken2string({Other, _}) when is_atom(Other) -> - io_lib:format("~w", [Other]); + io_lib:write(Other); yecctoken2string(Other) -> io_lib:write(Other). @@ -164,7 +193,7 @@ yecctoken2string(Other) -> --file("yeccparser.erl", 168). +-file("yeccparser.erl", 196). yeccpars2(0=S, Cat, Ss, Stack, T, Ts, Tzr) -> yeccpars2_0(S, Cat, Ss, Stack, T, Ts, Tzr); @@ -248,7 +277,9 @@ yeccpars2_0(S, integer, Ss, Stack, T, Ts, Tzr) -> yeccpars2_0(S, reserved_word, Ss, Stack, T, Ts, Tzr) -> yeccpars1(S, 8, Ss, Stack, T, Ts, Tzr); yeccpars2_0(S, var, Ss, Stack, T, Ts, Tzr) -> - yeccpars1(S, 9, Ss, Stack, T, Ts, Tzr). + yeccpars1(S, 9, Ss, Stack, T, Ts, Tzr); +yeccpars2_0(_, _, _, _, T, _, _) -> + yeccerror(T). yeccpars2_1(S, atom, Ss, Stack, T, Ts, Tzr) -> yeccpars1(S, 6, Ss, Stack, T, Ts, Tzr); @@ -267,10 +298,14 @@ yeccpars2_2(_S, Cat, Ss, Stack, T, Ts, Tzr) -> yeccgoto_grammar(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr). yeccpars2_3(S, '->', Ss, Stack, T, Ts, Tzr) -> - yeccpars1(S, 10, Ss, Stack, T, Ts, Tzr). + yeccpars1(S, 10, Ss, Stack, T, Ts, Tzr); +yeccpars2_3(_, _, _, _, T, _, _) -> + yeccerror(T). -yeccpars2_4(_S, '$end', _Ss, Stack, _T, _Ts, _Tzr) -> - {ok, hd(Stack)}. +yeccpars2_4(_S, '$end', _Ss, Stack, _T, _Ts, _Tzr) -> + {ok, hd(Stack)}; +yeccpars2_4(_, _, _, _, T, _, _) -> + yeccerror(T). yeccpars2_5(_S, Cat, Ss, Stack, T, Ts, Tzr) -> yeccgoto_grammar(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr). @@ -317,7 +352,9 @@ yeccpars2_13(_S, Cat, Ss, Stack, T, Ts, Tzr) -> yeccgoto_symbols(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). yeccpars2_14(S, dot, Ss, Stack, T, Ts, Tzr) -> - yeccpars1(S, 29, Ss, Stack, T, Ts, Tzr). + yeccpars1(S, 29, Ss, Stack, T, Ts, Tzr); +yeccpars2_14(_, _, _, _, T, _, _) -> + yeccerror(T). yeccpars2_15(S, '->', Ss, Stack, T, Ts, Tzr) -> yeccpars1(S, 18, Ss, Stack, T, Ts, Tzr); @@ -338,7 +375,9 @@ yeccpars2_15(S, reserved_word, Ss, Stack, T, Ts, Tzr) -> yeccpars2_15(S, string, Ss, Stack, T, Ts, Tzr) -> yeccpars1(S, 26, Ss, Stack, T, Ts, Tzr); yeccpars2_15(S, var, Ss, Stack, T, Ts, Tzr) -> - yeccpars1(S, 27, Ss, Stack, T, Ts, Tzr). + yeccpars1(S, 27, Ss, Stack, T, Ts, Tzr); +yeccpars2_15(_, _, _, _, T, _, _) -> + yeccerror(T). yeccpars2_16(_S, Cat, Ss, Stack, T, Ts, Tzr) -> [_|Nss] = Ss, @@ -414,10 +453,14 @@ yeccpars2_29(_S, Cat, Ss, Stack, T, Ts, Tzr) -> yeccgoto_rule(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). yeccpars2_30(S, dot, Ss, Stack, T, Ts, Tzr) -> - yeccpars1(S, 35, Ss, Stack, T, Ts, Tzr). + yeccpars1(S, 35, Ss, Stack, T, Ts, Tzr); +yeccpars2_30(_, _, _, _, T, _, _) -> + yeccerror(T). yeccpars2_31(S, dot, Ss, Stack, T, Ts, Tzr) -> - yeccpars1(S, 34, Ss, Stack, T, Ts, Tzr). + yeccpars1(S, 34, Ss, Stack, T, Ts, Tzr); +yeccpars2_31(_, _, _, _, T, _, _) -> + yeccerror(T). yeccpars2_32(S, string, Ss, Stack, T, Ts, Tzr) -> yeccpars1(S, 32, Ss, Stack, T, Ts, Tzr); @@ -486,7 +529,7 @@ yeccgoto_tokens(15=_S, Cat, Ss, Stack, T, Ts, Tzr) -> yeccgoto_tokens(17=_S, Cat, Ss, Stack, T, Ts, Tzr) -> yeccpars2_28(_S, Cat, Ss, Stack, T, Ts, Tzr). --compile({inline,{yeccpars2_6_,1}}). +-compile({inline,yeccpars2_6_/1}). -file("yeccgramm.yrl", 44). yeccpars2_6_(__Stack0) -> [__1 | __Stack] = __Stack0, @@ -494,7 +537,7 @@ yeccpars2_6_(__Stack0) -> symbol ( __1 ) end | __Stack]. --compile({inline,{yeccpars2_7_,1}}). +-compile({inline,yeccpars2_7_/1}). -file("yeccgramm.yrl", 45). yeccpars2_7_(__Stack0) -> [__1 | __Stack] = __Stack0, @@ -502,7 +545,7 @@ yeccpars2_7_(__Stack0) -> symbol ( __1 ) end | __Stack]. --compile({inline,{yeccpars2_8_,1}}). +-compile({inline,yeccpars2_8_/1}). -file("yeccgramm.yrl", 46). yeccpars2_8_(__Stack0) -> [__1 | __Stack] = __Stack0, @@ -510,7 +553,7 @@ yeccpars2_8_(__Stack0) -> symbol ( __1 ) end | __Stack]. --compile({inline,{yeccpars2_9_,1}}). +-compile({inline,yeccpars2_9_/1}). -file("yeccgramm.yrl", 43). yeccpars2_9_(__Stack0) -> [__1 | __Stack] = __Stack0, @@ -518,14 +561,14 @@ yeccpars2_9_(__Stack0) -> symbol ( __1 ) end | __Stack]. --compile({inline,{yeccpars2_11_,1}}). +-compile({inline,yeccpars2_11_/1}). -file("yeccgramm.yrl", 40). yeccpars2_11_(__Stack0) -> [begin { erlang_code , [ { atom , 0 , '$undefined' } ] } end | __Stack0]. --compile({inline,{yeccpars2_12_,1}}). +-compile({inline,yeccpars2_12_/1}). -file("yeccgramm.yrl", 35). yeccpars2_12_(__Stack0) -> [__1 | __Stack] = __Stack0, @@ -533,7 +576,7 @@ yeccpars2_12_(__Stack0) -> [ __1 ] end | __Stack]. --compile({inline,{yeccpars2_13_,1}}). +-compile({inline,yeccpars2_13_/1}). -file("yeccgramm.yrl", 36). yeccpars2_13_(__Stack0) -> [__2,__1 | __Stack] = __Stack0, @@ -541,7 +584,7 @@ yeccpars2_13_(__Stack0) -> [ __1 | __2 ] end | __Stack]. --compile({inline,{yeccpars2_16_,1}}). +-compile({inline,yeccpars2_16_/1}). -file("yeccgramm.yrl", 39). yeccpars2_16_(__Stack0) -> [__2,__1 | __Stack] = __Stack0, @@ -549,7 +592,7 @@ yeccpars2_16_(__Stack0) -> { erlang_code , __2 } end | __Stack]. --compile({inline,{yeccpars2_17_,1}}). +-compile({inline,yeccpars2_17_/1}). -file("yeccgramm.yrl", 41). yeccpars2_17_(__Stack0) -> [__1 | __Stack] = __Stack0, @@ -557,7 +600,7 @@ yeccpars2_17_(__Stack0) -> [ __1 ] end | __Stack]. --compile({inline,{yeccpars2_18_,1}}). +-compile({inline,yeccpars2_18_/1}). -file("yeccgramm.yrl", 55). yeccpars2_18_(__Stack0) -> [__1 | __Stack] = __Stack0, @@ -565,7 +608,7 @@ yeccpars2_18_(__Stack0) -> { '->' , line_of ( __1 ) } end | __Stack]. --compile({inline,{yeccpars2_19_,1}}). +-compile({inline,yeccpars2_19_/1}). -file("yeccgramm.yrl", 56). yeccpars2_19_(__Stack0) -> [__1 | __Stack] = __Stack0, @@ -573,7 +616,7 @@ yeccpars2_19_(__Stack0) -> { ':' , line_of ( __1 ) } end | __Stack]. --compile({inline,{yeccpars2_24_,1}}). +-compile({inline,yeccpars2_24_/1}). -file("yeccgramm.yrl", 53). yeccpars2_24_(__Stack0) -> [__1 | __Stack] = __Stack0, @@ -581,7 +624,7 @@ yeccpars2_24_(__Stack0) -> { value_of ( __1 ) , line_of ( __1 ) } end | __Stack]. --compile({inline,{yeccpars2_25_,1}}). +-compile({inline,yeccpars2_25_/1}). -file("yeccgramm.yrl", 54). yeccpars2_25_(__Stack0) -> [__1 | __Stack] = __Stack0, @@ -589,7 +632,7 @@ yeccpars2_25_(__Stack0) -> { value_of ( __1 ) , line_of ( __1 ) } end | __Stack]. --compile({inline,{yeccpars2_28_,1}}). +-compile({inline,yeccpars2_28_/1}). -file("yeccgramm.yrl", 42). yeccpars2_28_(__Stack0) -> [__2,__1 | __Stack] = __Stack0, @@ -597,7 +640,7 @@ yeccpars2_28_(__Stack0) -> [ __1 | __2 ] end | __Stack]. --compile({inline,{yeccpars2_29_,1}}). +-compile({inline,yeccpars2_29_/1}). -file("yeccgramm.yrl", 33). yeccpars2_29_(__Stack0) -> [__5,__4,__3,__2,__1 | __Stack] = __Stack0, @@ -605,7 +648,7 @@ yeccpars2_29_(__Stack0) -> { rule , [ __1 | __3 ] , __4 } end | __Stack]. --compile({inline,{yeccpars2_32_,1}}). +-compile({inline,yeccpars2_32_/1}). -file("yeccgramm.yrl", 37). yeccpars2_32_(__Stack0) -> [__1 | __Stack] = __Stack0, @@ -613,7 +656,7 @@ yeccpars2_32_(__Stack0) -> [ __1 ] end | __Stack]. --compile({inline,{yeccpars2_33_,1}}). +-compile({inline,yeccpars2_33_/1}). -file("yeccgramm.yrl", 38). yeccpars2_33_(__Stack0) -> [__2,__1 | __Stack] = __Stack0, @@ -621,7 +664,7 @@ yeccpars2_33_(__Stack0) -> [ __1 | __2 ] end | __Stack]. --compile({inline,{yeccpars2_34_,1}}). +-compile({inline,yeccpars2_34_/1}). -file("yeccgramm.yrl", 32). yeccpars2_34_(__Stack0) -> [__3,__2,__1 | __Stack] = __Stack0, @@ -629,7 +672,7 @@ yeccpars2_34_(__Stack0) -> { __1 , __2 } end | __Stack]. --compile({inline,{yeccpars2_35_,1}}). +-compile({inline,yeccpars2_35_/1}). -file("yeccgramm.yrl", 31). yeccpars2_35_(__Stack0) -> [__3,__2,__1 | __Stack] = __Stack0, diff --git a/lib/parsetools/test/yecc_SUITE.erl b/lib/parsetools/test/yecc_SUITE.erl index 61e2456323..93949a074a 100644 --- a/lib/parsetools/test/yecc_SUITE.erl +++ b/lib/parsetools/test/yecc_SUITE.erl @@ -298,8 +298,8 @@ syntax(Config) when is_list(Config) -> {_,[{L1,_,{undefined_function,{yeccpars2_2_,1}}}, {L2,_,{bad_inline,{yeccpars2_2_,1}}}]}], []} = compile:file(Parserfile1, [basic_validation,return]), - ?line L1 = 24 + SzYeccPre, - ?line L2 = 31 + SzYeccPre + ?line L1 = 28 + SzYeccPre, + ?line L2 = 35 + SzYeccPre end(), %% Bad macro in action. OTP-7224. @@ -316,8 +316,8 @@ syntax(Config) when is_list(Config) -> {_,[{L1,_,{undefined_function,{yeccpars2_2_,1}}}, {L2,_,{bad_inline,{yeccpars2_2_,1}}}]}], []} = compile:file(Parserfile1, [basic_validation,return]), - ?line L1 = 24 + SzYeccPre, - ?line L2 = 31 + SzYeccPre + ?line L1 = 28 + SzYeccPre, + ?line L2 = 35 + SzYeccPre end(), %% Check line numbers. OTP-7224. @@ -1584,8 +1584,8 @@ otp_7292(Config) when is_list(Config) -> {L2,_,{bad_inline,{yeccpars2_2_,1}}}]}], [{_,[{16,_,{unused_function,{foo,0}}}]}]} = compile:file(Parserfile1, [basic_validation, return]), - ?line L1 = 34 + SzYeccPre, - ?line L2 = 41 + SzYeccPre + ?line L1 = 38 + SzYeccPre, + ?line L2 = 45 + SzYeccPre end(), YeccPre = filename:join(Dir, "yeccpre.hrl"), @@ -1602,8 +1602,8 @@ otp_7292(Config) when is_list(Config) -> {L2,_,{bad_inline,{yeccpars2_2_,1}}}]}], [{_,[{16,_,{unused_function,{foo,0}}}]}]} = compile:file(Parserfile1, [basic_validation, return]), - ?line L1 = 33 + SzYeccPre, - ?line L2 = 40 + SzYeccPre + ?line L1 = 37 + SzYeccPre, + ?line L2 = 44 + SzYeccPre end(), file:delete(YeccPre), diff --git a/lib/parsetools/vsn.mk b/lib/parsetools/vsn.mk index f3e2dc0fb4..46915baed6 100644 --- a/lib/parsetools/vsn.mk +++ b/lib/parsetools/vsn.mk @@ -1 +1 @@ -PARSETOOLS_VSN = 2.0.3 +PARSETOOLS_VSN = 2.0.4 diff --git a/lib/public_key/doc/src/cert_records.xml b/lib/public_key/doc/src/cert_records.xml index 8cfe57f670..0d6113acef 100644 --- a/lib/public_key/doc/src/cert_records.xml +++ b/lib/public_key/doc/src/cert_records.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> @@ -37,7 +37,7 @@ <p>This chapter briefly describes erlang records derived from asn1 specifications used to handle X509 certificates. The intent is to describe the data types and not to specify the meaning of each - component for this we refer you to RFC 3280. + component for this we refer you to RFC 5280. </p> <p>Use the following include directive to get access to the @@ -45,11 +45,7 @@ <code> -include_lib("public_key/include/public_key.hrl"). </code> - <p>The used specification is available in <c>OTP-PKIX.asn1</c>, - which is an amelioration of - the <c>PKIX1Explicit88.asn1</c>, <c>PKIX1Implicit88.asn1</c> - and <c>PKIX1Algorithms88.asn1</c> modules. - You find all these modules in the <c>asn1</c> subdirectory + <p>The used asn1 specifications are available <c>asn1</c> subdirectory of the application <c>public_key</c>. </p> @@ -62,6 +58,9 @@ marker="public_key">public key reference manual </seealso> or follows here.</p> + <p><c>oid() - a tuple of integers + as generated by the asn1 compiler.</c></p> + <p><c>time() = uct_time() | general_time()</c></p> <p><c>uct_time() = {utcTime, "YYMMDDHHMMSSZ"} </c></p> @@ -119,9 +118,31 @@ algorithm, % oid() parameters % asn1_der_encoded() }. +</code> + +<code> +#'OTPCertificate'{ + tbsCertificate, % #'OTPTBSCertificate'{} + signatureAlgorithm, % #'SignatureAlgorithm' + signature % {0, binary()} - asn1 compact bitstring + }. + +#'OTPTBSCertificate'{ + version, % v1 | v2 | v3 + serialNumber, % integer() + signature, % #'SignatureAlgorithm' + issuer, % {rdnSequence, [#AttributeTypeAndValue'{}]} + validity, % #'Validity'{} + subject, % {rdnSequence, [#AttributeTypeAndValue'{}]} + subjectPublicKeyInfo, % #'SubjectPublicKeyInfo'{} + issuerUniqueID, % binary() | asn1_novalue + subjectUniqueID, % binary() | asn1_novalue + extensions % [#'Extension'{}] + }. + #'SignatureAlgorithm'{ algorithm, % id_signature_algorithm() - parameters % public_key_params() + parameters % asn1_novalue | #'Dss-Parms'{} }. </code> diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index dc9a96906f..c72719fac4 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> @@ -34,11 +34,7 @@ <modulesummary> API module for public key infrastructure.</modulesummary> <description> <p>This module provides functions to handle public key infrastructure - from RFC 3280 - X.509 certificates (will later be upgraded to RFC 5280) - and some parts of the PKCS-standard. - Currently this application is mainly used by the new - ssl implementation. The API is yet under construction - and only a few of the functions are currently documented and thereby supported. + from RFC 5280 - X.509 certificates and some parts of the PKCS-standard. </p> </description> @@ -62,37 +58,37 @@ <p><c>boolean() = true | false</c></p> - <p><c>string = [bytes()]</c></p> - - <p><c>asn1_der_encoded() = binary() | [bytes()]</c></p> + <p><c>string = [bytes()]</c></p> + + <p><c>der_encoded() = binary() </c></p> - <p><c>der_bin() = binary() </c></p> + <p><c>decrypt_der() = binary() </c></p> - <p><c>oid() - a tuple of integers - as generated by the asn1 compiler.</c></p> - - <p><c>public_key() = rsa_public_key() | dsa_public_key()</c></p> + <p><c>pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| + 'DSAPrivateKey' | 'DHParameter'</c></p> + <p><c>pem_entry () = {pki_asn1_type(), der_encoded() | decrypt_der(), not_encrypted | + {"DES-CBC" | "DES-EDE3-CBC", crypto:rand_bytes(8)}}.</c></p> + <p><c>rsa_public_key() = #'RSAPublicKey'{}</c></p> <p><c>rsa_private_key() = #'RSAPrivateKey'{} </c></p> - <p><c>dsa_public_key() = integer() </c></p> - - <p><c>public_key_params() = dsa_key_params() </c></p> - - <p><c>dsa_key_params() = #'Dss-Parms'{} </c></p> - - <p><c>private_key() = rsa_private_key() | dsa_private_key()</c></p> + <p><c>dsa_public_key() = {integer(), #'Dss-Parms'{}} </c></p> <p><c>rsa_private_key() = #'RSAPrivateKey'{} </c></p> <p><c>dsa_private_key() = #'DSAPrivateKey'{}</c></p> + + <p><c> public_crypt_options() = [{rsa_pad, rsa_padding()}]. </c></p> - <p><c>x509_certificate() = "#Certificate{}"</c></p> - - <p><c>x509_tbs_certificate() = #'TBSCertificate'{} </c></p> - + <p><c> rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' + | 'rsa_no_padding'</c></p> + + <p><c> rsa_digest_type() = 'md5' | 'sha' </c></p> + + <p><c> dss_digest_type() = 'none' | 'sha' </c></p> + <!-- <p><c>policy_tree() = [Root, Children]</c></p> --> <!-- <p><c>Root = #policy_tree_node{}</c></p> --> @@ -121,197 +117,301 @@ <!-- that would satisfy this policy in the certificate x+1. </item> --> <!-- </taglist> --> </section> - -<funcs> - <func> - <name>decode_private_key(KeyInfo) -> </name> - <name>decode_private_key(KeyInfo, Password) -> {ok, PrivateKey} | {error, Reason}</name> - <fsummary> Decodes an asn1 der encoded private key.</fsummary> - <type> - <v> KeyInfo = {KeyType, der_bin(), ChipherInfo} </v> - <d> As returned from pem_to_der/1 for private keys</d> - <v> KeyType = rsa_private_key | dsa_private_key </v> - <v> ChipherInfo = opaque() | no_encryption </v> - <d> ChipherInfo may contain encryption parameters if the private key is password - protected, these are opaque to the user just pass the value returned by pem_to_der/1 - to this function.</d> - <v> Password = string() </v> - <d>Must be specified if CipherInfo =/= no_encryption</d> - <v> PrivateKey = private_key() </v> - <v> Reason = term() </v> - </type> - <desc> - <p>Decodes an asn1 der encoded private key.</p> - </desc> - </func> - + +<funcs> + <func> - <name>pem_to_der(File) -> {ok, [Entry]}</name> - <fsummary>Reads a PEM file and translates it into its asn1 der - encoded parts.</fsummary> + <name>decrypt_private(CipherText, Key [, Options]) -> binary()</name> + <fsummary>Public key decryption.</fsummary> <type> - <v>File = path()</v> - <v>Password = string()</v> - <v>Entry = {entry_type(), der_bin(), CipherInfo}</v> - <v> ChipherInfo = opaque() | no_encryption </v> - <d> ChipherInfo may contain encryption parameters if the private key is password - protected, these will be handled by the function decode_private_key/2. </d> - <v>entry_type() = cert | cert_req | rsa_private_key | dsa_private_key | - dh_params </v> + <v>CipherText = binary()</v> + <v>Key = rsa_private_key()</v> + <v>Options = public_crypt_options()</v> </type> <desc> - <p>Reads a PEM file and translates it into its asn1 der - encoded parts.</p> + <p>Public key decryption using the private key.</p> + </desc> + </func> + + <func> + <name>decrypt_public(CipherText, Key [, Options]) - > binary()</name> + <fsummary></fsummary> + <type> + <v>CipherText = binary()</v> + <v>Key = rsa_public_key()</v> + <v>Options = public_crypt_options()</v> + </type> + <desc> + <p> Public key decryption using the public key.</p> </desc> </func> - - <func> - <name>pkix_decode_cert(Cert, Type) -> {ok, DecodedCert} | {error, Reason}</name> - <fsummary> Decodes an asn1 der encoded pkix certificate. </fsummary> - <type> - <v>Cert = asn1_der_encoded() </v> - <v>Type = plain | otp</v> - <v>DecodeCert = x509_certificate() </v> - <d>When type is specified as otp the asn1 spec OTP-PKIX.asn1 is used to decode known - extensions and enhance the signature field in - #'Certificate'{} and '#TBSCertificate'{}. This is currently used by the new ssl - implementation but not documented and supported for the public_key application.</d> - <v>Reason = term() </v> + + <func> + <name>der_decode(Asn1type, Der) -> term()</name> + <fsummary> Decodes a public key asn1 der encoded entity.</fsummary> + <type> + <v>Asn1Type = atom() -</v> + <d> Asn1 type present in the public_key applications + asn1 specifications.</d> + <v>Der = der_encoded()</v> </type> - <desc> - <p> Decodes an asn1 encoded pkix certificate.</p> + <desc> + <p> Decodes a public key asn1 der encoded entity.</p> </desc> </func> + + <func> + <name>der_encode(Asn1Type, Entity) -> der_encoded()</name> + <fsummary> Encodes a public key entity with asn1 DER encoding.</fsummary> + <type> + <v>Asn1Type = atom()</v> + <d> Asn1 type present in the public_key applications + asn1 specifications.</d> + <v>Entity = term() - The erlang representation of <c> Asn1Type</c></v> + </type> + <desc> + <p> Encodes a public key entity with asn1 DER encoding.</p> + </desc> + </func> + + <func> + <name>pem_decode(PemBin) -> [pem_entry()]</name> + <fsummary>Decode PEM binary data and return + entries as asn1 der encoded entities. </fsummary> + <type> + <v>PemBin = binary()</v> + <d>Example {ok, PemBin} = file:read_file("cert.pem").</d> + </type> + <desc> + <p>Decode PEM binary data and return + entries as asn1 der encoded entities.</p> + </desc> + </func> + + <func> + <name>pem_encode(PemEntries) -> binary()</name> + <fsummary>Creates a PEM binary</fsummary> + <type> + <v> PemEntries = [pem_entry()] </v> + </type> + <desc> + <p>Creates a PEM binary</p> + </desc> + </func> + + <func> + <name>pem_entry_decode(PemEntry [, Password]) -> term()</name> + <fsummary>Decodes a pem entry.</fsummary> + <type> + <v> PemEntry = pem_entry() </v> + <v> Password = string() </v> + </type> + <desc> + <p>Decodes a pem entry. pem_decode/1 returns a list of + pem entries.</p> + </desc> + </func> + + <func> + <name>pem_entry_encode(Asn1Type, Entity [,{CipherInfo, Password}]) -> pem_entry()</name> + <fsummary> Creates a pem entry that can be feed to pem_encode/1.</fsummary> + <type> + <v>Asn1Type = atom()</v> + <v>Entity = term()</v> + <v>CipherInfo = {"DES-CBC" | "DES-EDE3-CBC", crypto:rand_bytes(8)}</v> + <v>Password = string()</v> + </type> + <desc> + <p> Creates a pem entry that can be feed to pem_encode/1.</p> + </desc> + </func> + + <func> + <name>encrypt_private(PlainText, Key) -> binary()</name> + <fsummary> Public key encryption using the private key.</fsummary> + <type> + <v>PlainText = binary()</v> + <v>Key = rsa_private_key()</v> + </type> + <desc> + <p> Public key encryption using the private key.</p> + </desc> + </func> + + <func> + <name>encrypt_public(PlainText, Key) -> binary()</name> + <fsummary> Public key encryption using the public key.</fsummary> + <type> + <v>PlainText = binary()</v> + <v>Key = rsa_public_key()</v> + </type> + <desc> + <p> Public key encryption using the public key.</p> + </desc> + </func> -<!-- <func> --> -<!-- <name> pkix_encode_cert(Cert) -> {ok, EncodedCert} | {error, Reason}</name> --> -<!-- <fsummary>Encodes a certificate record using asn1. </fsummary> --> -<!-- <type> --> -<!-- <v>Cert = x509_certificate() </v> --> -<!-- <v>EncodedCert = asn1_der_encoded() </v> --> -<!-- <v>Reason = term() </v> --> -<!-- </type> --> -<!-- <desc> --> -<!-- <p> Encodes a certificate record using asn1.</p> --> -<!-- </desc> --> -<!-- </func> --> + <func> + <name> pkix_decode_cert(Cert, otp|plain) -> #'Certificate'{} | #'OTPCertificate'{}</name> + <fsummary> Decodes an asn1 der encoded pkix x509 certificate.</fsummary> + <type> + <v>Cert = der_encoded()</v> + </type> + <desc> + <p>Decodes an asn1 der encoded pkix certificate. The otp option + will use the customized asn1 specification OTP-PKIX.asn1 for + decoding and also recursively decode most of the standard + parts.</p> + </desc> + </func> -<!-- <func> --> -<!-- <name>pkix_path_validation(TrustedCert, CertChain, Options) -> {ok, Result} | {error, Reason}</name> --> - -<!-- <fsummary>Performs a basic path validation according to RFC 3280</fsummary> --> -<!-- <type> --> -<!-- <v>TrustedCert = asn1_der_encoded()</v> --> -<!-- <v>CertChain = [asn1_der_encoded()]</v> --> -<!-- <v>Options = [{Option, Value}]</v> --> -<!-- <v>Result = {{algorithm(), public_key(), --> -<!-- public_key_params()}, policy_tree()}</v> --> -<!-- </type> --> + <func> + <name>pkix_encode(Asn1Type, Entity, otp | plain) -> der_encoded()</name> + <fsummary>Der encodes a pkix x509 certificate or part of such a + certificate.</fsummary> + <type> + <v>Asn1Type = atom()</v> + <d>The asn1 type can be 'Certificate', 'OTPCertificate' or a subtype of either .</d> + </type> + <desc> + <p>Der encodes a pkix x509 certificate or part of such a + certificate. This function must be used for encoding certificates or parts of certificates + that are decoded/created on the otp format, whereas for the plain format this + function will directly call der_encode/2. </p> + </desc> + </func> + + <func> + <name>pkix_is_issuer(Cert, IssuerCert) -> boolean()</name> + <fsummary> Checks if <c>IssuerCert</c> issued <c>Cert</c> </fsummary> + <type> + <v>Cert = der_encode() | #'OTPCertificate'{}</v> + <v>IssuerCert = der_encode() | #'OTPCertificate'{}</v> + </type> + <desc> + <p> Checks if <c>IssuerCert</c> issued <c>Cert</c> </p> + </desc> + </func> + + <func> + <name>pkix_is_fixed_dh_cert(Cert) -> boolean()</name> + <fsummary> Checks if a Certificate is a fixed Diffie-Hellman Cert.</fsummary> + <type> + <v>Cert = der_encode() | #'OTPCertificate'{}</v> + </type> + <desc> + <p> Checks if a Certificate is a fixed Diffie-Hellman Cert.</p> + </desc> + </func> + + <func> + <name>pkix_is_self_signed(Cert) -> boolean()</name> + <fsummary> Checks if a Certificate is self signed.</fsummary> + <type> + <v>Cert = der_encode() | #'OTPCertificate'{}</v> + </type> + <desc> + <p> Checks if a Certificate is self signed.</p> + </desc> + </func> + + <func> + <name>pkix_issuer_id(Cert, IssuedBy) -> {ok, IssuerID} | {error, Reason}</name> + <fsummary> Returns the issuer id.</fsummary> + <type> + <v>Cert = der_encode() | #'OTPCertificate'{}</v> + <v>IssuedBy = self | other</v> + <v>IssuerID = {integer(), {rdnSequence, [#'AttributeTypeAndValue'{}]}}</v> + <d>The issuer id consists of the serial number and the issuers name.</d> + <v>Reason = term()</v> + </type> + <desc> + <p> Returns the issuer id.</p> + </desc> + </func> -<!-- <desc> --> -<!-- <p>Available options are: </p> --> -<!-- <taglist> --> -<!-- <tag>{validate_extension_fun, fun()}</tag> --> -<!-- <item> A fun behaving according to the following outline: --> -<!-- <code> --> -<!-- [...] --> -<!-- ValidateExtensionFun = fun(Extensions, UserState) -> --> -<!-- validate_extensions(Extensions, UserState, []) --> -<!-- end, --> -<!-- [...] --> + <func> + <name>pkix_normalize_name(Issuer) -> Normalized</name> + <fsummary>Normalizes a issuer name so that it can be easily + compared to another issuer name. </fsummary> + <type> + <v>Issuer = {rdnSequence,[#'AttributeTypeAndValue'{}]}</v> + <v>Normalized = {rdnSequence, [#'AttributeTypeAndValue'{}]}</v> + </type> + <desc> + <p>Normalizes a issuer name so that it can be easily + compared to another issuer name.</p> + </desc> + </func> + + <!-- <func> --> + <!-- <name>pkix_path_validation()</name> --> + <!-- <fsummary> Performs a basic path validation according to RFC 5280.</fsummary> --> + <!-- <type> --> + <!-- <v></v> --> + <!-- </type> --> + <!-- <desc> --> + <!-- <p> Performs a basic path validation according to RFC 5280.</p> --> + <!-- </desc> --> + <!-- </func> --> -<!-- validate_extensions([], UserState, UnknowExtension) -> --> -<!-- {UserState, UnknowExtension}; --> -<!-- validate_extensions([#'Extension'{} = Ext | Rest], UserState, UnknowExtension) -> --> -<!-- case valid_extension(Ext) of --> -<!-- {true, NewUserState} -> --> -<!-- validate_extensions(Rest, NewUserState, UnknowExtension); --> -<!-- unknown -> --> -<!-- validate_extensions(Rest, UserState, [Ext | UnknowExtension]); --> -<!-- {false, Reason} -> --> -<!-- throw(bad_cert, Reason) --> -<!-- end. --> -<!-- </code> --> - -<!-- </item> --> - -<!-- <tag>{policy_set, [oid()]}</tag> --> -<!-- <item>A set of certificate policy --> -<!-- identifiers naming the policies that are acceptable to the --> -<!-- certificate user. If the user is not concerned about --> -<!-- certificate policy there is no need --> -<!-- to set this option. Defaults to the --> -<!-- special value [?anyPolicy]. --> -<!-- </item> --> - -<!-- <tag>{policy_mapping, boolean()}</tag> --> -<!-- <item>Indicates if policy --> -<!-- mapping, initially, is allowed in the certification path. --> -<!-- Defaults to false. --> -<!-- </item> --> - -<!-- <tag> {explicit_policy, boolean()}</tag> --> -<!-- <item>Indicates if the path, initially, must be --> -<!-- valid for at least one of the certificate policies in the user --> -<!-- specified policy set. --> -<!-- Defaults to false. --> -<!-- </item> --> + + <func> + <name>pkix_sign(#'OTPTBSCertificate'{}, Key) -> der_encode()</name> + <fsummary>Signs certificate.</fsummary> + <type> + <v>Key = rsa_public_key() | dsa_public_key()</v> + </type> + <desc> + <p>Signs a 'OTPTBSCertificate'. Returns the corresponding + der encoded certificate.</p> + </desc> + </func> -<!-- <tag>{inhibit_any_policy, boolean()}</tag> --> -<!-- <item>Indicates whether the anyPolicy OID, initially, should --> -<!-- be processed if it is included in a certificate. --> -<!-- Defaults to false. --> -<!-- </item> --> - -<!-- </taglist> --> - -<!-- <p>Performs a basic path validation according to RFC 3280, --> -<!-- e.i. signature validation, time validation, issuer validation, --> -<!-- alternative subject name validation, CRL validation, policy --> -<!-- validation and checks that no unknown extensions --> -<!-- are marked as critical. The option <c>validate_extension_fun</c> --> -<!-- may be used to validate application specific extensions. If --> -<!-- a validation criteria is found to be invalid the validation process --> -<!-- will immediately be stopped and this functions will return --> -<!-- {error, Reason}. --> -<!-- </p> --> -<!-- </desc> --> -<!-- </func> --> + <func> + <name>pkix_verify(Cert, Key) -> boolean()</name> + <fsummary> Verify pkix x.509 certificate signature.</fsummary> + <type> + <v>Cert = der_encode()</v> + <v>Key = rsa_public_key() | dsa_public_key()</v> + </type> + <desc> + <p> Verify pkix x.509 certificate signature.</p> + </desc> + </func> -<!-- <func> --> -<!-- <name>sign(DigestOrTBSCert, Key) -> </name> --> -<!-- <name>sign(DigestOrTBSCert, Key, KeyParams) -> {ok, SignatureOrDerCert} | {error, Reason}</name> --> -<!-- <fsummary>Signs Digest/Certificate using Key.</fsummary> --> -<!-- <type> --> -<!-- <v>DigestOrTBSCert = binary() | x509_tbs_certificate()</v> --> -<!-- <v>Key = private_key()</v> --> -<!-- <v>SignatureORDerCert = binary() | der_bin() </v> --> -<!-- <v>Reason = term() </v> --> -<!-- </type> --> -<!-- <desc> --> -<!-- <p> Signs Digest/Certificate using Key, in the later --> -<!-- case a der encoded x509_certificate() will be returned. </p> --> -<!-- </desc> --> -<!-- </func> --> + <func> + <name>sign(Msg, DigestType, Key) -> binary()</name> + <fsummary> Create digital signature.</fsummary> + <type> + <v>Msg = binary()</v> + <d>The msg is either the binary "plain text" data to be + signed or in the case that digest type is <c>none</c> + it is the hashed value of "plain text" i.e. the digest.</d> + <v>DigestType = rsa_digest_type() | dsa_digest_type()</v> + <v>Key = rsa_public_key() | dsa_public_key()</v> + </type> + <desc> + <p> Creates a digital signature.</p> + </desc> + </func> -<!-- <func> --> -<!-- <name>verify_signature(Digest, Signature, Key) -> </name> --> -<!-- <name>verify_signature(DerCert, Key, KeyParams) -> </name> --> -<!-- <name>verify_signature(Digest, Signature, Key, Params) -> Verified </name> --> -<!-- <fsummary> Verifies the signature. </fsummary> --> -<!-- <type> --> -<!-- <v>Digest = binary() </v> --> -<!-- <v>DerCert = der_bin() </v> --> -<!-- <v>Signature = binary() </v> --> -<!-- <v>Key = public_key() </v> --> -<!-- <v>Params = key_params()</v> --> -<!-- <v>Verified = boolean()</v> --> -<!-- </type> --> -<!-- <desc> --> -<!-- <p> Verifies the signature Signature. If the key is an rsa-key no --> -<!-- paramters are neeed.</p> --> -<!-- </desc> --> -<!-- </func> --> + <func> + <name>verify(Msg, DigestType, Signature, Key) -> boolean()</name> + <fsummary>Verifies a digital signature.</fsummary> + <type> + <v>Msg = binary()</v> + <d>The msg is either the binary "plain text" data + or in the case that digest type is <c>none</c> + it is the hashed value of "plain text" i.e. the digest.</d> + <v>DigestType = rsa_digest_type() | dsa_digest_type()</v> + <v>Signature = binary()</v> + <v>Key = rsa_public_key() | dsa_public_key()</v> + </type> + <desc> + <p>Verifies a digital signature</p> + </desc> + </func> + </funcs> </erlref> diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl index fbce10f0eb..6503321042 100644 --- a/lib/public_key/include/public_key.hrl +++ b/lib/public_key/include/public_key.hrl @@ -59,4 +59,13 @@ interim_reasons_mask }). + +-type der_encoded() :: binary(). +-type decrypt_der() :: binary(). +-type pki_asn1_type() :: 'Certificate' | 'RSAPrivateKey' + | 'DSAPrivateKey' | 'DHParameter'. +-type pem_entry() :: {pki_asn1_type(), der_encoded() | decrypt_der(), + not_encrypted | {Cipher :: string(), Salt :: binary()}}. +-type asn1_type() :: atom(). %% see "OTP-PUB-KEY.hrl + -endif. % -ifdef(public_key). diff --git a/lib/public_key/src/Makefile b/lib/public_key/src/Makefile index c30399f33a..51f405361b 100644 --- a/lib/public_key/src/Makefile +++ b/lib/public_key/src/Makefile @@ -42,8 +42,7 @@ MODULES = \ public_key \ pubkey_pem \ pubkey_cert \ - pubkey_cert_records \ - pubkey_crypto + pubkey_cert_records HRL_FILES = $(INCLUDE)/public_key.hrl diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl index 0651dcec29..64fc8ab5bc 100644 --- a/lib/public_key/src/pubkey_cert.erl +++ b/lib/public_key/src/pubkey_cert.erl @@ -23,14 +23,14 @@ -include("public_key.hrl"). --export([verify_signature/3, - init_validation_state/3, prepare_for_next_cert/2, +-export([init_validation_state/3, prepare_for_next_cert/2, validate_time/3, validate_signature/6, validate_issuer/4, validate_names/6, validate_revoked_status/3, validate_extensions/4, validate_unknown_extensions/3, normalize_general_name/1, digest_type/1, is_self_signed/1, - is_issuer/2, issuer_id/2, is_fixed_dh_cert/1]). + is_issuer/2, issuer_id/2, is_fixed_dh_cert/1, + verify_data/1]). -define(NULL, 0). @@ -38,10 +38,22 @@ %% Internal application API %%==================================================================== -verify_signature(DerCert, Key, KeyParams) -> - {ok, OtpCert} = pubkey_cert_records:decode_cert(DerCert, otp), - verify_signature(OtpCert, DerCert, Key, KeyParams). +%%-------------------------------------------------------------------- +-spec verify_data(der_encoded()) -> {md5 | sha, binary(), binary()}. +%% +%% Description: Extracts data from DerCert needed to call public_key:verify/4. +%%-------------------------------------------------------------------- +verify_data(DerCert) -> + {ok, OtpCert} = pubkey_cert_records:decode_cert(DerCert), + extract_verify_data(OtpCert, DerCert). +%%-------------------------------------------------------------------- +-spec init_validation_state(#'OTPCertificate'{}, integer(), list()) -> + #path_validation_state{}. +%% +%% Description: Creates inital version of path_validation_state for +%% basic path validation of x509 certificates. +%%-------------------------------------------------------------------- init_validation_state(#'OTPCertificate'{} = OtpCert, DefaultPathLen, Options) -> PolicyTree = #policy_tree_node{valid_policy = ?anyPolicy, @@ -66,6 +78,12 @@ init_validation_state(#'OTPCertificate'{} = OtpCert, DefaultPathLen, cert_num = 0}, prepare_for_next_cert(OtpCert, State). +%%-------------------------------------------------------------------- +-spec prepare_for_next_cert(#'OTPCertificate'{}, #path_validation_state{}) -> + #path_validation_state{}. +%% +%% Description: Update path_validation_state for next iteration. +%%-------------------------------------------------------------------- prepare_for_next_cert(OtpCert, ValidationState = #path_validation_state{ working_public_key_algorithm = PrevAlgo, working_public_key_parameters = @@ -92,7 +110,13 @@ prepare_for_next_cert(OtpCert, ValidationState = #path_validation_state{ working_issuer_name = Issuer, cert_num = ValidationState#path_validation_state.cert_num + 1 }. - + + %%-------------------------------------------------------------------- +-spec validate_time(#'OTPCertificate'{}, list(), boolean()) -> list(). +%% +%% Description: Check that the certificate validity period includes the +%% current time. +%%-------------------------------------------------------------------- validate_time(OtpCert, AccErr, Verify) -> TBSCert = OtpCert#'OTPCertificate'.tbsCertificate, {'Validity', NotBeforeStr, NotAfterStr} @@ -107,7 +131,12 @@ validate_time(OtpCert, AccErr, Verify) -> false -> not_valid({bad_cert, cert_expired}, Verify, AccErr) end. - +%%-------------------------------------------------------------------- +-spec validate_issuer(#'OTPCertificate'{}, term(), list(), boolean()) -> list(). +%% +%% Description: Check that the certificate issuer name is the working_issuer_name +%% in path_validation_state. +%%-------------------------------------------------------------------- validate_issuer(OtpCert, Issuer, AccErr, Verify) -> TBSCert = OtpCert#'OTPCertificate'.tbsCertificate, case is_issuer(Issuer, TBSCert#'OTPTBSCertificate'.issuer) of @@ -116,7 +145,15 @@ validate_issuer(OtpCert, Issuer, AccErr, Verify) -> _ -> not_valid({bad_cert, invalid_issuer}, Verify, AccErr) end. - +%%-------------------------------------------------------------------- +-spec validate_signature(#'OTPCertificate'{}, der_encoded(), + term(),term(), list(), boolean()) -> list(). + +%% +%% Description: Check that the signature on the certificate can be verified using +%% working_public_key_algorithm, the working_public_key, and +%% the working_public_key_parameters in path_validation_state. +%%-------------------------------------------------------------------- validate_signature(OtpCert, DerCert, Key, KeyParams, AccErr, Verify) -> @@ -126,7 +163,12 @@ validate_signature(OtpCert, DerCert, Key, KeyParams, false -> not_valid({bad_cert, invalid_signature}, Verify, AccErr) end. - +%%-------------------------------------------------------------------- +-spec validate_names(#'OTPCertificate'{}, list(), list(), + term(), list(), boolean())-> list(). +%% +%% Description: Validate Subject Alternative Name. +%%-------------------------------------------------------------------- validate_names(OtpCert, Permit, Exclude, Last, AccErr, Verify) -> case is_self_signed(OtpCert) andalso (not Last) of true -> @@ -143,8 +185,10 @@ validate_names(OtpCert, Permit, Exclude, Last, AccErr, Verify) -> Name = [{directoryName, Subject}|EmailAddress], AltNames = case AltSubject of - undefined -> []; - _ -> AltSubject#'Extension'.extnValue + undefined -> + []; + _ -> + AltSubject#'Extension'.extnValue end, case (is_permitted(Name, Permit) andalso @@ -159,28 +203,36 @@ validate_names(OtpCert, Permit, Exclude, Last, AccErr, Verify) -> end end. - -%% See rfc3280 4.1.2.6 Subject: regarding emails. -extract_email({rdnSequence, List}) -> - extract_email2(List). -extract_email2([[#'AttributeTypeAndValue'{type=?'id-emailAddress', - value=Mail}]|_]) -> - [{rfc822Name, Mail}]; -extract_email2([_|Rest]) -> - extract_email2(Rest); -extract_email2([]) -> []. - +%%-------------------------------------------------------------------- +-spec validate_revoked_status(#'OTPCertificate'{}, boolean(), list()) -> + list(). +%% +%% Description: Check if certificate has been revoked. +%%-------------------------------------------------------------------- validate_revoked_status(_OtpCert, _Verify, AccErr) -> + %% TODO: Implement or leave for application?! %% true | %% throw({bad_cert, cert_revoked}) AccErr. - +%%-------------------------------------------------------------------- +-spec validate_extensions(#'OTPCertificate'{}, #path_validation_state{}, + boolean(), list())-> + {#path_validation_state{}, + UnknownExtensions :: list(), AccErrors :: list()}. +%% +%% Description: Check extensions included in basic path validation. +%%-------------------------------------------------------------------- validate_extensions(OtpCert, ValidationState, Verify, AccErr) -> TBSCert = OtpCert#'OTPCertificate'.tbsCertificate, Extensions = TBSCert#'OTPTBSCertificate'.extensions, validate_extensions(Extensions, ValidationState, no_basic_constraint, is_self_signed(OtpCert), [], Verify, AccErr). +%-------------------------------------------------------------------- + -spec validate_unknown_extensions(list(), list(), boolean())-> list(). +%% +%% Description: Check that all critical extensions has been handled. +%%-------------------------------------------------------------------- validate_unknown_extensions([], AccErr, _Verify) -> AccErr; validate_unknown_extensions([#'Extension'{critical = true} | _], @@ -190,27 +242,38 @@ validate_unknown_extensions([#'Extension'{critical = false} | Rest], AccErr, Verify) -> validate_unknown_extensions(Rest, AccErr, Verify). +%%-------------------------------------------------------------------- +-spec normalize_general_name({rdnSequence, term()}) -> {rdnSequence, term()}. +%% +%% Description: Normalizes a general name so that it can be easily +%% compared to another genral name. +%%-------------------------------------------------------------------- normalize_general_name({rdnSequence, Issuer}) -> - NormIssuer = normalize_general_name(Issuer), - {rdnSequence, NormIssuer}; - -normalize_general_name(Issuer) -> - Normalize = fun([{Description, Type, {printableString, Value}}]) -> - NewValue = string:to_lower(strip_spaces(Value)), - [{Description, Type, {printableString, NewValue}}]; - (Atter) -> - Atter - end, - lists:sort(lists:map(Normalize, Issuer)). + NormIssuer = do_normalize_general_name(Issuer), + {rdnSequence, NormIssuer}. +%%-------------------------------------------------------------------- +-spec is_self_signed(#'OTPCertificate'{}) -> boolean(). +%% +%% Description: Checks if the certificate is self signed. +%%-------------------------------------------------------------------- is_self_signed(#'OTPCertificate'{tbsCertificate= #'OTPTBSCertificate'{issuer = Issuer, subject = Subject}}) -> is_issuer(Issuer, Subject). - +%%-------------------------------------------------------------------- +-spec is_issuer({rdnSequence, term()}, {rdnSequence, term()}) -> boolean(). +%% +%% Description: Checks if <Issuer> issued <Candidate>. +%%-------------------------------------------------------------------- is_issuer({rdnSequence, Issuer}, {rdnSequence, Candidate}) -> is_dir_name(Issuer, Candidate, true). - +%%-------------------------------------------------------------------- +-spec issuer_id(#'OTPCertificate'{}, self | other) -> + {ok, {integer(), term()}} | {error, issuer_not_found}. +%% +%% Description: Extracts the issuer id from a certificate if possible. +%%-------------------------------------------------------------------- issuer_id(Otpcert, other) -> TBSCert = Otpcert#'OTPCertificate'.tbsCertificate, Extensions = extensions_list(TBSCert#'OTPTBSCertificate'.extensions), @@ -227,7 +290,12 @@ issuer_id(Otpcert, self) -> SerialNr = TBSCert#'OTPTBSCertificate'.serialNumber, {ok, {SerialNr, normalize_general_name(Issuer)}}. - +%%-------------------------------------------------------------------- +-spec is_fixed_dh_cert(#'OTPCertificate'{}) -> boolean(). +%% +%% Description: Checks if the certificate can be be used +%% for DH key agreement. +%%-------------------------------------------------------------------- is_fixed_dh_cert(#'OTPCertificate'{tbsCertificate = #'OTPTBSCertificate'{subjectPublicKeyInfo = SubjectPublicKeyInfo, @@ -238,6 +306,24 @@ is_fixed_dh_cert(#'OTPCertificate'{tbsCertificate = %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- +do_normalize_general_name(Issuer) -> + Normalize = fun([{Description, Type, {printableString, Value}}]) -> + NewValue = string:to_lower(strip_spaces(Value)), + [{Description, Type, {printableString, NewValue}}]; + (Atter) -> + Atter + end, + lists:sort(lists:map(Normalize, Issuer)). + +%% See rfc3280 4.1.2.6 Subject: regarding emails. +extract_email({rdnSequence, List}) -> + extract_email2(List). +extract_email2([[#'AttributeTypeAndValue'{type=?'id-emailAddress', + value=Mail}]|_]) -> + [{rfc822Name, Mail}]; +extract_email2([_|Rest]) -> + extract_email2(Rest); +extract_email2([]) -> []. extensions_list(asn1_NOVALUE) -> []; @@ -249,17 +335,22 @@ not_valid(Error, true, _) -> not_valid(Error, false, AccErrors) -> [Error | AccErrors]. -verify_signature(OtpCert, DerCert, Key, KeyParams) -> - %% Signature is an ASN1 compact bit string +extract_verify_data(OtpCert, DerCert) -> {0, Signature} = OtpCert#'OTPCertificate'.signature, SigAlgRec = OtpCert#'OTPCertificate'.signatureAlgorithm, SigAlg = SigAlgRec#'SignatureAlgorithm'.algorithm, - EncTBSCert = encoded_tbs_cert(DerCert), - verify(SigAlg, EncTBSCert, Signature, Key, KeyParams). + PlainText = encoded_tbs_cert(DerCert), + DigestType = digest_type(SigAlg), + {DigestType, PlainText, Signature}. -verify(Alg, PlainText, Signature, Key, KeyParams) -> - public_key:verify_signature(PlainText, digest_type(Alg), - Signature, Key, KeyParams). +verify_signature(OtpCert, DerCert, Key, KeyParams) -> + {DigestType, PlainText, Signature} = extract_verify_data(OtpCert, DerCert), + case Key of + #'RSAPublicKey'{} -> + public_key:verify(PlainText, DigestType, Signature, Key); + _ -> + public_key:verify(PlainText, DigestType, Signature, {Key, KeyParams}) + end. encoded_tbs_cert(Cert) -> {ok, PKIXCert} = @@ -411,8 +502,8 @@ validate_extensions([#'Extension'{extnID = ?'id-ce-basicConstraints', ValidationState = #path_validation_state{max_path_length = Len}, _, SelfSigned, UnknownExtensions, Verify, AccErr) -> - Length = if SelfSigned -> min(N, Len); - true -> min(N, Len-1) + Length = if SelfSigned -> erlang:min(N, Len); + true -> erlang:min(N, Len-1) end, validate_extensions(Rest, ValidationState#path_validation_state{max_path_length = @@ -603,11 +694,6 @@ is_valid_subject_alt_name({_, [_|_]}) -> is_valid_subject_alt_name({_, _}) -> false. -min(N, M) when N =< M -> - N; -min(_, M) -> - M. - is_ip_address(Address) -> case inet_parse:address(Address) of {ok, _} -> @@ -670,10 +756,11 @@ split_auth_path(URIPart) -> end. split_uri(UriPart, SplitChar, NoMatchResult, SkipLeft, SkipRight) -> - case regexp:first_match(UriPart, SplitChar) of - {match, Match, _} -> - {string:substr(UriPart, 1, Match - SkipLeft), - string:substr(UriPart, Match + SkipRight, length(UriPart))}; + case re:run(UriPart, SplitChar) of + {match,[{Start, _}]} -> + StrPos = Start + 1, + {string:substr(UriPart, 1, StrPos - SkipLeft), + string:substr(UriPart, StrPos + SkipRight, length(UriPart))}; nomatch -> NoMatchResult end. @@ -926,7 +1013,7 @@ add_policy_constraints(ExpPolicy, MapPolicy, policy_constraint(Current, asn1_NOVALUE, _) -> Current; policy_constraint(Current, New, CertNum) -> - min(Current, New + CertNum). + erlang:min(Current, New + CertNum). process_policy_tree(_,_, ?NULL) -> ?NULL; diff --git a/lib/public_key/src/pubkey_cert_records.erl b/lib/public_key/src/pubkey_cert_records.erl index ac04e1c2cb..20b322b4a4 100644 --- a/lib/public_key/src/pubkey_cert_records.erl +++ b/lib/public_key/src/pubkey_cert_records.erl @@ -23,30 +23,61 @@ -include("public_key.hrl"). --export([decode_cert/2, encode_cert/1, encode_tbs_cert/1, transform/2]). +-export([decode_cert/1, transform/2]). %%==================================================================== %% Internal application API %%==================================================================== -decode_cert(DerCert, plain) -> - 'OTP-PUB-KEY':decode('Certificate', DerCert); -decode_cert(DerCert, otp) -> +%%-------------------------------------------------------------------- +-spec decode_cert(der_encoded()) -> {ok, #'OTPCertificate'{}}. +%% +%% Description: Recursively decodes a Certificate. +%%-------------------------------------------------------------------- +decode_cert(DerCert) -> {ok, Cert} = 'OTP-PUB-KEY':decode('OTPCertificate', DerCert), #'OTPCertificate'{tbsCertificate = TBS} = Cert, {ok, Cert#'OTPCertificate'{tbsCertificate = decode_tbs(TBS)}}. -encode_cert(Cert = #'Certificate'{}) -> - {ok, EncCert} = 'OTP-PUB-KEY':encode('Certificate', Cert), - list_to_binary(EncCert); -encode_cert(C = #'OTPCertificate'{tbsCertificate = TBS}) -> - Cert = C#'OTPCertificate'{tbsCertificate=encode_tbs(TBS)}, - {ok, EncCert} = 'OTP-PUB-KEY':encode('OTPCertificate', Cert), - list_to_binary(EncCert). - -encode_tbs_cert(TBS) -> - {ok, EncTBSCert} = 'OTP-PUB-KEY':encode('OTPTBSCertificate', encode_tbs(TBS)), - list_to_binary(EncTBSCert). +%%-------------------------------------------------------------------- +-spec transform(term(), encode | decode) ->term(). +%% +%% Description: Transforms between encoded and decode otp formated +%% certificate parts. +%%-------------------------------------------------------------------- + +transform(#'OTPCertificate'{tbsCertificate = TBS} = Cert, encode) -> + Cert#'OTPCertificate'{tbsCertificate=encode_tbs(TBS)}; +transform(#'OTPCertificate'{tbsCertificate = TBS} = Cert, decode) -> + Cert#'OTPCertificate'{tbsCertificate=decode_tbs(TBS)}; +transform(#'OTPTBSCertificate'{}= TBS, encode) -> + encode_tbs(TBS); +transform(#'OTPTBSCertificate'{}= TBS, decode) -> + decode_tbs(TBS); +transform(#'AttributeTypeAndValue'{type=Id,value=Value0} = ATAV, Func) -> + {ok, Value} = + case attribute_type(Id) of + Type when is_atom(Type) -> 'OTP-PUB-KEY':Func(Type, Value0); + _UnknownType -> {ok, Value0} + end, + ATAV#'AttributeTypeAndValue'{value=Value}; +transform(AKI = #'AuthorityKeyIdentifier'{authorityCertIssuer=ACI},Func) -> + AKI#'AuthorityKeyIdentifier'{authorityCertIssuer=transform(ACI,Func)}; +transform(List = [{directoryName, _}],Func) -> + [{directoryName, transform(Value,Func)} || {directoryName, Value} <- List]; +transform({directoryName, Value},Func) -> + {directoryName, transform(Value,Func)}; +transform({rdnSequence, SeqList},Func) when is_list(SeqList) -> + {rdnSequence, + lists:map(fun(Seq) -> + lists:map(fun(Element) -> transform(Element,Func) end, Seq) + end, SeqList)}; +transform(#'NameConstraints'{permittedSubtrees=Permitted, excludedSubtrees=Excluded}, Func) -> + #'NameConstraints'{permittedSubtrees=transform_sub_tree(Permitted,Func), + excludedSubtrees=transform_sub_tree(Excluded,Func)}; + +transform(Other,_) -> + Other. %%-------------------------------------------------------------------- %%% Internal functions @@ -132,31 +163,6 @@ encode_extensions(Exts) -> end end, Exts). -transform(#'AttributeTypeAndValue'{type=Id,value=Value0} = ATAV, Func) -> - {ok, Value} = - case attribute_type(Id) of - Type when is_atom(Type) -> 'OTP-PUB-KEY':Func(Type, Value0); - _UnknownType -> {ok, Value0} - end, - ATAV#'AttributeTypeAndValue'{value=Value}; -transform(AKI = #'AuthorityKeyIdentifier'{authorityCertIssuer=ACI},Func) -> - AKI#'AuthorityKeyIdentifier'{authorityCertIssuer=transform(ACI,Func)}; -transform(List = [{directoryName, _}],Func) -> - [{directoryName, transform(Value,Func)} || {directoryName, Value} <- List]; -transform({directoryName, Value},Func) -> - {directoryName, transform(Value,Func)}; -transform({rdnSequence, SeqList},Func) when is_list(SeqList) -> - {rdnSequence, - lists:map(fun(Seq) -> - lists:map(fun(Element) -> transform(Element,Func) end, Seq) - end, SeqList)}; -transform(#'NameConstraints'{permittedSubtrees=Permitted, excludedSubtrees=Excluded}, Func) -> - #'NameConstraints'{permittedSubtrees=transform_sub_tree(Permitted,Func), - excludedSubtrees=transform_sub_tree(Excluded,Func)}; - -transform(Other,_) -> - Other. - encode_tbs(TBS=#'OTPTBSCertificate'{issuer=Issuer0, subject=Subject0, subjectPublicKeyInfo=Spki0, diff --git a/lib/public_key/src/pubkey_crypto.erl b/lib/public_key/src/pubkey_crypto.erl deleted file mode 100644 index 7b7abb1c56..0000000000 --- a/lib/public_key/src/pubkey_crypto.erl +++ /dev/null @@ -1,171 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2008-2010. 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% -%% - -%% -%% Description: Functions that call the crypto driver. - --module(pubkey_crypto). - --include("public_key.hrl"). - --export([encrypt_public/3, decrypt_private/3, - encrypt_private/3, decrypt_public/3, - sign/2, sign/3, verify/5, gen_key/2]). - --define(UINT32(X), X:32/unsigned-big-integer). - -%%==================================================================== -%% Internal application API -%%==================================================================== - -%%-------------------------------------------------------------------- -%% Function: encrypt(PlainText, Key, Padding) -> Encrypted -%% -%% PlainText = binary() -%% Key = rsa_public_key() | rsa_private_key() -%% Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding -%% Encrypted = binary() -%% -%% Description: Public key encrypts PlainText. -%%-------------------------------------------------------------------- -encrypt_public(PlainText, #'RSAPublicKey'{modulus=N,publicExponent=E}, - Padding) -> - crypto:rsa_public_encrypt(PlainText, [crypto:mpint(E),crypto:mpint(N)], - Padding); -encrypt_public(PlainText, #'RSAPrivateKey'{modulus=N,publicExponent=E}, - Padding) -> - crypto:rsa_public_encrypt(PlainText, [crypto:mpint(E),crypto:mpint(N)], - Padding). - -encrypt_private(PlainText, #'RSAPrivateKey'{modulus = N, - publicExponent = E, - privateExponent = D}, Padding) -> - crypto:rsa_private_encrypt(PlainText, [crypto:mpint(E), - crypto:mpint(N), - crypto:mpint(D)], Padding). - -%%-------------------------------------------------------------------- -%% Function: decrypt(CipherText, Key) -> PlainText -%% -%% ChipherText = binary() -%% Key = rsa_private_key() -%% Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding -%% PlainText = binary() -%% -%% Description: Uses private key to decrypt public key encrypted data. -%%-------------------------------------------------------------------- -decrypt_private(CipherText, - #'RSAPrivateKey'{modulus = N,publicExponent = E, - privateExponent = D}, - Padding) -> - crypto:rsa_private_decrypt(CipherText, - [crypto:mpint(E), crypto:mpint(N), - crypto:mpint(D)], Padding). -decrypt_public(CipherText, #'RSAPublicKey'{modulus = N, publicExponent = E}, - Padding) -> - crypto:rsa_public_decrypt(CipherText,[crypto:mpint(E), crypto:mpint(N)], - Padding); -decrypt_public(CipherText, #'RSAPrivateKey'{modulus = N, publicExponent = E}, - Padding) -> - crypto:rsa_public_decrypt(CipherText,[crypto:mpint(E), crypto:mpint(N)], - Padding). - -%%-------------------------------------------------------------------- -%% Function: sign(PlainText, Key) -> -%% sign(DigestType, PlainText, Key) -> Signature -%% -%% DigestType = sha | md5 -%% PlainText = binary() -%% Key = rsa_private_key() | dsa_private_key() -%% Signature = binary() -%% -%% Description: Signs PlainText using Key. -%%-------------------------------------------------------------------- -sign(PlainText, Digest) -> - sign(sha, PlainText, Digest). - -sign(DigestType, PlainText, #'RSAPrivateKey'{modulus = N, publicExponent = E, - privateExponent = D}) -> - crypto:rsa_sign(DigestType, sized_binary(PlainText), [crypto:mpint(E), - crypto:mpint(N), - crypto:mpint(D)]); - -sign(none, Hash, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) -> - crypto:dss_sign(none, Hash, - [crypto:mpint(P), crypto:mpint(Q), - crypto:mpint(G), crypto:mpint(X)]); - -sign(sha, PlainText, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) -> - crypto:dss_sign(sized_binary(PlainText), - [crypto:mpint(P), crypto:mpint(Q), - crypto:mpint(G), crypto:mpint(X)]). - -%%-------------------------------------------------------------------- -%% Function: verify(DigestType, PlainText, Signature, Key) -> true | false -%% -%% DigestType = sha | md5 -%% PlainText = binary() -%% Signature = binary() -%% Key = rsa_public_key() | dsa_public_key() -%% -%% Description: Verifies the signature <Signature>. -%%-------------------------------------------------------------------- -verify(DigestType, PlainText, Signature, - #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}, _) -> - crypto:rsa_verify(DigestType, - sized_binary(PlainText), - sized_binary(Signature), - [crypto:mpint(Exp), crypto:mpint(Mod)]); - -verify(none, Hash, Signature, Key, #'Dss-Parms'{p = P, q = Q, g = G}) -> - crypto:dss_verify(none, Hash, - sized_binary(Signature), - [crypto:mpint(P), crypto:mpint(Q), - crypto:mpint(G), crypto:mpint(Key)]); - -verify(sha, PlainText, Signature, Key, #'Dss-Parms'{p = P, q = Q, g = G}) -> - crypto:dss_verify(sized_binary(PlainText), - sized_binary(Signature), - [crypto:mpint(P), crypto:mpint(Q), - crypto:mpint(G), crypto:mpint(Key)]). - - -%%-------------------------------------------------------------------- -%% Function: gen_key(Type, Params) -> -%% Type = diffie_hellman -%% Params = [P,G] | [Y, P, G] -%% Description: Generates keys. -%% ----------------------------------------------------------------- -gen_key(diffie_hellman, [Y, P, G]) -> - crypto:dh_generate_key(crypto:mpint(Y), [crypto:mpint(P), - crypto:mpint(G)]); -gen_key(diffie_hellman, [P, G]) -> - crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]). - -%%% TODO: Support rsa, dss key_gen - -%%-------------------------------------------------------------------- -%%% Internal functions -%%-------------------------------------------------------------------- -sized_binary(Binary) when is_binary(Binary) -> - Size = size(Binary), - <<?UINT32(Size), Binary/binary>>; -sized_binary(List) -> - sized_binary(list_to_binary(List)). - diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl index 65879f1bbe..31d881973a 100644 --- a/lib/public_key/src/pubkey_pem.erl +++ b/lib/public_key/src/pubkey_pem.erl @@ -40,7 +40,10 @@ -module(pubkey_pem). --export([read_file/1, read_file/2, write_file/2, decode/2]). +-include("public_key.hrl"). + +-export([encode/1, decode/1, decipher/2, cipher/3]). +%% Backwards compatibility -export([decode_key/2]). -define(ENCODED_LINE_LENGTH, 64). @@ -48,28 +51,82 @@ %%==================================================================== %% Internal application API %%==================================================================== -read_file(File) -> - read_file(File, no_passwd). -read_file(File, Passwd) -> - {ok, Bin} = file:read_file(File), - decode(Bin, Passwd). +%%-------------------------------------------------------------------- +-spec decode(binary()) -> [pem_entry()]. +%% +%% Description: Decodes a PEM binary. +%%-------------------------------------------------------------------- +decode(Bin) -> + decode_pem_entries(split_bin(Bin), []). -write_file(File, Ds) -> - file:write_file(File, encode_file(Ds)). +%%-------------------------------------------------------------------- +-spec encode([pem_entry()]) -> iolist(). +%% +%% Description: Encodes a list of PEM entries. +%%-------------------------------------------------------------------- +encode(PemEntries) -> + encode_pem_entries(PemEntries). -decode_key({_Type, Bin, not_encrypted}, _) -> - Bin; -decode_key({_Type, Bin, {Chipher,Salt}}, Password) -> - decode_key(Bin, Password, Chipher, Salt). +%%-------------------------------------------------------------------- +-spec decipher({pki_asn1_type(), decrypt_der(),{Cipher :: string(), Salt :: binary()}}, string()) -> + der_encoded(). +%% +%% Description: Deciphers a decrypted pem entry. +%%-------------------------------------------------------------------- +decipher({_, DecryptDer, {Cipher,Salt}}, Password) -> + decode_key(DecryptDer, Password, Cipher, Salt). -decode(Bin, Passwd) -> - decode_file(split_bin(Bin), Passwd). +%%-------------------------------------------------------------------- +-spec cipher(der_encoded(),{Cipher :: string(), Salt :: binary()} , string()) -> binary(). +%% +%% Description: Ciphers a PEM entry +%%-------------------------------------------------------------------- +cipher(Der, {Cipher,Salt}, Password)-> + encode_key(Der, Password, Cipher, Salt). %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- +encode_pem_entries(Entries) -> + [encode_pem_entry(Entry) || Entry <- Entries]. + +encode_pem_entry({Asn1Type, Der, not_encrypted}) -> + StartStr = pem_start(Asn1Type), + [StartStr, "\n", b64encode_and_split(Der), pem_end(StartStr) ,"\n\n"]; +encode_pem_entry({Asn1Type, Der, {Cipher, Salt}}) -> + StartStr = pem_start(Asn1Type), + [StartStr,"\n", pem_decrypt(),"\n", pem_decrypt_info(Cipher, Salt),"\n", + b64encode_and_split(Der), pem_end(StartStr) ,"\n\n"]. + +decode_pem_entries([], Entries) -> + lists:reverse(Entries); +decode_pem_entries([<<>>], Entries) -> + lists:reverse(Entries); +decode_pem_entries([<<>> | Lines], Entries) -> + decode_pem_entries(Lines, Entries); +decode_pem_entries([Start| Lines], Entries) -> + case pem_end(Start) of + undefined -> + decode_pem_entries(Lines, Entries); + _End -> + {Entry, RestLines} = join_entry(Lines, []), + decode_pem_entries(RestLines, [decode_pem_entry(Start, Entry) | Entries]) + end. +decode_pem_entry(Start, [<<"Proc-Type: 4,ENCRYPTED", _/binary>>, Line | Lines]) -> + Asn1Type = asn1_type(Start), + Cs = erlang:iolist_to_binary(Lines), + Decoded = base64:mime_decode(Cs), + [_, DekInfo0] = string:tokens(binary_to_list(Line), ": "), + [Cipher, Salt] = string:tokens(DekInfo0, ","), + {Asn1Type, Decoded, {Cipher, unhex(Salt)}}; +decode_pem_entry(Start, Lines) -> + Asn1Type = asn1_type(Start), + Cs = erlang:iolist_to_binary(Lines), + Der = base64:mime_decode(Cs), + {Asn1Type, Der, not_encrypted}. + split_bin(Bin) -> split_bin(0, Bin). @@ -85,88 +142,26 @@ split_bin(N, Bin) -> split_bin(N+1, Bin) end. -decode_file(Bin, Passwd) -> - decode_file(Bin, [], [Passwd]). - -decode_file([<<"-----BEGIN CERTIFICATE REQUEST-----", _/binary>>|Rest], Ens, Info) -> - decode_file2(Rest, [], Ens, cert_req, Info); -decode_file([<<"-----BEGIN CERTIFICATE-----", _/binary>>|Rest], Ens, Info) -> - decode_file2(Rest, [], Ens, cert, Info); -decode_file([<<"-----BEGIN RSA PRIVATE KEY-----", _/binary>>|Rest], Ens, Info) -> - decode_file2(Rest, [], Ens, rsa_private_key, Info); -decode_file([<<"-----BEGIN DSA PRIVATE KEY-----", _/binary>>|Rest], Ens, Info) -> - decode_file2(Rest, [], Ens, dsa_private_key, Info); -decode_file([<<"-----BEGIN DH PARAMETERS-----", _/binary>>|Rest], Ens, Info) -> - decode_file2(Rest, [], Ens, dh_params, Info); -decode_file([_|Rest], Ens, Info) -> - decode_file(Rest, Ens, Info); -decode_file([], Ens, _Info) -> - {ok, lists:reverse(Ens)}. - -decode_file2([<<"Proc-Type: 4,ENCRYPTED", _/binary>>| Rest0], RLs, Ens, Tag, Info0) -> - [InfoLine|Rest] = Rest0, - Info = dek_info(InfoLine, Info0), - decode_file2(Rest, RLs, Ens, Tag, Info); -decode_file2([<<"-----END", _/binary>>| Rest], RLs, Ens, Tag, Info0) -> - Cs = erlang:iolist_to_binary(lists:reverse(RLs)), - Bin = base64:mime_decode(Cs), - case Info0 of - [Password, Cipher, SaltHex | Info1] -> - Salt = unhex(SaltHex), - Enc = {Cipher, Salt}, - Decoded = decode_key(Bin, Password, Cipher, Salt), - decode_file(Rest, [{Tag, Decoded, Enc}| Ens], Info1); - _ -> - decode_file(Rest, [{Tag, Bin, not_encrypted}| Ens], Info0) - end; -decode_file2([L|Rest], RLs, Ens, Tag, Info0) -> - decode_file2(Rest, [L|RLs], Ens, Tag, Info0); -decode_file2([], _, Ens, _, _) -> - {ok, lists:reverse(Ens)}. - -%% Support same as decode_file -encode_file(Ds) -> - lists:map( - fun({cert, Bin, not_encrypted}) -> - %% PKIX (X.509) - ["-----BEGIN CERTIFICATE-----\n", - b64encode_and_split(Bin), - "-----END CERTIFICATE-----\n\n"]; - ({cert_req, Bin, not_encrypted}) -> - %% PKCS#10 - ["-----BEGIN CERTIFICATE REQUEST-----\n", - b64encode_and_split(Bin), - "-----END CERTIFICATE REQUEST-----\n\n"]; - ({rsa_private_key, Bin, not_encrypted}) -> - %% PKCS#? - ["XXX Following key assumed not encrypted\n", - "-----BEGIN RSA PRIVATE KEY-----\n", - b64encode_and_split(Bin), - "-----END RSA PRIVATE KEY-----\n\n"]; - ({dsa_private_key, Bin, not_encrypted}) -> - %% PKCS#? - ["XXX Following key assumed not encrypted\n", - "-----BEGIN DSA PRIVATE KEY-----\n", - b64encode_and_split(Bin), - "-----END DSA PRIVATE KEY-----\n\n"] - end, Ds). - -dek_info(Line0, Info) -> - Line = binary_to_list(Line0), - [_, DekInfo0] = string:tokens(Line, ": "), - DekInfo1 = string:tokens(DekInfo0, ",\n"), - Info ++ DekInfo1. +b64encode_and_split(Bin) -> + split_lines(base64:encode(Bin)). -unhex(S) -> - unhex(S, []). +split_lines(<<Text:?ENCODED_LINE_LENGTH/binary, Rest/binary>>) -> + [Text, $\n | split_lines(Rest)]; +split_lines(Bin) -> + [Bin, $\n]. -unhex("", Acc) -> - list_to_binary(lists:reverse(Acc)); -unhex([D1, D2 | Rest], Acc) -> - unhex(Rest, [erlang:list_to_integer([D1, D2], 16) | Acc]). +%% Ignore white space at end of line +join_entry([<<"-----END CERTIFICATE-----", _/binary>>| Lines], Entry) -> + {lists:reverse(Entry), Lines}; +join_entry([<<"-----END RSA PRIVATE KEY-----", _/binary>>| Lines], Entry) -> + {lists:reverse(Entry), Lines}; +join_entry([<<"-----END DSA PRIVATE KEY-----", _/binary>>| Lines], Entry) -> + {lists:reverse(Entry), Lines}; +join_entry([<<"-----END DH PARAMETERS-----", _/binary>>| Lines], Entry) -> + {lists:reverse(Entry), Lines}; +join_entry([Line | Lines], Entry) -> + join_entry(Lines, [Line | Entry]). -decode_key(Data, no_passwd, _Alg, _Salt) -> - Data; decode_key(Data, Password, "DES-CBC", Salt) -> Key = password_to_key(Password, Salt, 8), IV = Salt, @@ -177,6 +172,16 @@ decode_key(Data, Password, "DES-EDE3-CBC", Salt) -> <<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key, crypto:des_ede3_cbc_decrypt(Key1, Key2, Key3, IV, Data). +encode_key(Data, Password, "DES-CBC", Salt) -> + Key = password_to_key(Password, Salt, 8), + IV = Salt, + crypto:des_cbc_encrypt(Key, IV, Data); +encode_key(Data, Password, "DES-EDE3-CBC", Salt) -> + Key = password_to_key(Password, Salt, 24), + IV = Salt, + <<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key, + crypto:des_ede3_cbc_encrypt(Key1, Key2, Key3, IV, Data). + password_to_key(Data, Salt, KeyLen) -> <<Key:KeyLen/binary, _/binary>> = password_to_key(<<>>, Data, Salt, KeyLen, <<>>), @@ -188,11 +193,58 @@ password_to_key(Prev, Data, Salt, Len, Acc) -> M = crypto:md5([Prev, Data, Salt]), password_to_key(M, Data, Salt, Len - size(M), <<Acc/binary, M/binary>>). -b64encode_and_split(Bin) -> - split_lines(base64:encode(Bin)). +unhex(S) -> + unhex(S, []). -split_lines(<<Text:?ENCODED_LINE_LENGTH/binary, Rest/binary>>) -> - [Text, $\n | split_lines(Rest)]; -split_lines(Bin) -> - [Bin, $\n]. +unhex("", Acc) -> + list_to_binary(lists:reverse(Acc)); +unhex([D1, D2 | Rest], Acc) -> + unhex(Rest, [erlang:list_to_integer([D1, D2], 16) | Acc]). + +hexify(L) -> [[hex_byte(B)] || B <- binary_to_list(L)]. + +hex_byte(B) when B < 16#10 -> ["0", erlang:integer_to_list(B, 16)]; +hex_byte(B) -> erlang:integer_to_list(B, 16). + +pem_start('Certificate') -> + <<"-----BEGIN CERTIFICATE-----">>; +pem_start('RSAPrivateKey') -> + <<"-----BEGIN RSA PRIVATE KEY-----">>; +pem_start('DSAPrivateKey') -> + <<"-----BEGIN DSA PRIVATE KEY-----">>; +pem_start('DHParameter') -> + <<"-----BEGIN DH PARAMETERS-----">>. + +pem_end(<<"-----BEGIN CERTIFICATE-----">>) -> + <<"-----END CERTIFICATE-----">>; +pem_end(<<"-----BEGIN RSA PRIVATE KEY-----">>) -> + <<"-----END RSA PRIVATE KEY-----">>; +pem_end(<<"-----BEGIN DSA PRIVATE KEY-----">>) -> + <<"-----END DSA PRIVATE KEY-----">>; +pem_end(<<"-----BEGIN DH PARAMETERS-----">>) -> + <<"-----END DH PARAMETERS-----">>; +pem_end(_) -> + undefined. + +asn1_type(<<"-----BEGIN CERTIFICATE-----">>) -> + 'Certificate'; +asn1_type(<<"-----BEGIN RSA PRIVATE KEY-----">>) -> + 'RSAPrivateKey'; +asn1_type(<<"-----BEGIN DSA PRIVATE KEY-----">>) -> + 'DSAPrivateKey'; +asn1_type(<<"-----BEGIN DH PARAMETERS-----">>) -> + 'DHParameter'. + +pem_decrypt() -> + <<"Proc-Type: 4,ENCRYPTED">>. + +pem_decrypt_info(Cipher, Salt) -> + io_lib:format("DEK-Info: ~s,~s", [Cipher, lists:flatten(hexify(Salt))]). +%%-------------------------------------------------------------------- +%%% Deprecated +%%-------------------------------------------------------------------- +decode_key({_Type, Bin, not_encrypted}, _) -> + Bin; +decode_key({_Type, Bin, {Chipher,Salt}}, Password) -> + decode_key(Bin, Password, Chipher, Salt). diff --git a/lib/public_key/src/public_key.app.src b/lib/public_key/src/public_key.app.src index d5e1705827..60487946fa 100644 --- a/lib/public_key/src/public_key.app.src +++ b/lib/public_key/src/public_key.app.src @@ -4,7 +4,6 @@ {modules, [ public_key, pubkey_pem, - pubkey_crypto, pubkey_cert, pubkey_cert_records, 'OTP-PUB-KEY' diff --git a/lib/public_key/src/public_key.appup.src b/lib/public_key/src/public_key.appup.src index 2eb5750923..c9d15b8747 100644 --- a/lib/public_key/src/public_key.appup.src +++ b/lib/public_key/src/public_key.appup.src @@ -1,6 +1,15 @@ %% -*- erlang -*- {"%VSN%", [ + {"0.7", + [ + {update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []}, + {update, public_key, soft, soft_purge, soft_purge, []}, + {update, pubkey_pem, soft, soft_purge, soft_purge, []}, + {update, pubkey_cert_records, soft, soft_purge, soft_purge, []} + {update, pubkey_cert, soft, soft_purge, soft_purge, []} + ] + }, {"0.6", [ {update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []}, @@ -22,6 +31,15 @@ } ], [ + {"0.7", + [ + {update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []}, + {update, public_key, soft, soft_purge, soft_purge, []}, + {update, pubkey_pem, soft, soft_purge, soft_purge, []}, + {update, pubkey_cert_records, soft, soft_purge, soft_purge, []} + {update, pubkey_cert, soft, soft_purge, soft_purge, []} + ] + }, {"0.6", [ {update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []}, diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 12354eee5d..95c3d714d3 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -23,239 +23,396 @@ -include("public_key.hrl"). --export([decode_private_key/1, decode_private_key/2, decode_dhparams/1, - decrypt_private/2, decrypt_private/3, encrypt_public/2, - encrypt_public/3, decrypt_public/2, decrypt_public/3, - encrypt_private/2, encrypt_private/3, gen_key/1, sign/2, sign/3, - verify_signature/3, verify_signature/4, verify_signature/5, - pem_to_der/1, pem_to_der/2, der_to_pem/2, - pkix_decode_cert/2, pkix_encode_cert/1, pkix_transform/2, - pkix_is_self_signed/1, pkix_is_fixed_dh_cert/1, +-export([pem_decode/1, pem_encode/1, + der_decode/2, der_encode/2, + pem_entry_decode/1, + pem_entry_decode/2, + pem_entry_encode/2, + pem_entry_encode/3, + pkix_decode_cert/2, pkix_encode/3, + encrypt_private/2, encrypt_private/3, + decrypt_private/2, decrypt_private/3, + encrypt_public/2, encrypt_public/3, + decrypt_public/2, decrypt_public/3, + sign/3, verify/4, + pkix_sign/2, pkix_verify/2, + pkix_is_self_signed/1, + pkix_is_fixed_dh_cert/1, + pkix_is_issuer/2, pkix_issuer_id/2, - pkix_is_issuer/2, pkix_normalize_general_name/1, + pkix_normalize_name/1, pkix_path_validation/3 ]). +%% Deprecated +-export([decode_private_key/1, decode_private_key/2, pem_to_der/1]). + +-deprecated({pem_to_der, 1, next_major_release}). +-deprecated({decode_private_key, 1, next_major_release}). +-deprecated({decode_private_key, 2, next_major_release}). + +-type rsa_public_key() :: #'RSAPublicKey'{}. +-type rsa_private_key() :: #'RSAPrivateKey'{}. +-type dsa_private_key() :: #'DSAPrivateKey'{}. +-type dsa_public_key() :: {integer(), #'Dss-Parms'{}}. +-type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' + | 'rsa_no_padding'. +-type public_crypt_options() :: [{rsa_pad, rsa_padding()}]. +-type rsa_digest_type() :: 'md5' | 'sha'. +-type dss_digest_type() :: 'none' | 'sha'. + +-define(UINT32(X), X:32/unsigned-big-integer). + %%==================================================================== %% API %%==================================================================== %%-------------------------------------------------------------------- -%% Function: decode_private_key(KeyInfo [,Password]) -> -%% {ok, PrivateKey} | {error, Reason} -%% -%% KeyInfo = {Type, der_bin(), ChipherInfo} - as returned from -%% pem_to_der/[1,2] for private keys -%% Type = rsa_private_key | dsa_private_key -%% ChipherInfo = opaque() | no_encryption +-spec pem_decode(binary()) -> [pem_entry()]. +%% +%% Description: Decode PEM binary data and return +%% entries as asn1 der encoded entities. +%%-------------------------------------------------------------------- +pem_decode(PemBin) when is_binary(PemBin) -> + pubkey_pem:decode(PemBin). + +%%-------------------------------------------------------------------- +-spec pem_encode([pem_entry()]) -> binary(). %% -%% Description: Decodes an asn1 der encoded private key. +%% Description: Creates a PEM binary. %%-------------------------------------------------------------------- -decode_private_key(KeyInfo) -> - decode_private_key(KeyInfo, no_passwd). +pem_encode(PemEntries) when is_list(PemEntries) -> + iolist_to_binary(pubkey_pem:encode(PemEntries)). -decode_private_key(KeyInfo = {rsa_private_key, _, _}, Password) -> - DerEncoded = pubkey_pem:decode_key(KeyInfo, Password), - 'OTP-PUB-KEY':decode('RSAPrivateKey', DerEncoded); -decode_private_key(KeyInfo = {dsa_private_key, _, _}, Password) -> - DerEncoded = pubkey_pem:decode_key(KeyInfo, Password), - 'OTP-PUB-KEY':decode('DSAPrivateKey', DerEncoded). +%%-------------------------------------------------------------------- +-spec pem_entry_decode(pem_entry(), [string()]) -> term(). +% +%% Description: Decodes a pem entry. pem_decode/1 returns a list of +%% pem entries. +%%-------------------------------------------------------------------- +pem_entry_decode({Asn1Type, Der, not_encrypted}) when is_atom(Asn1Type), + is_binary(Der) -> + der_decode(Asn1Type, Der). +pem_entry_decode({Asn1Type, Der, not_encrypted}, _) when is_atom(Asn1Type), + is_binary(Der) -> + der_decode(Asn1Type, Der); +pem_entry_decode({Asn1Type, CryptDer, {Cipher, Salt}} = PemEntry, + Password) when is_atom(Asn1Type), + is_binary(CryptDer), + is_list(Cipher), + is_binary(Salt), + erlang:byte_size(Salt) == 8 + -> + Der = pubkey_pem:decipher(PemEntry, Password), + der_decode(Asn1Type, Der). +%%-------------------------------------------------------------------- +-spec pem_entry_encode(pki_asn1_type(), term()) -> pem_entry(). +-spec pem_entry_encode(pki_asn1_type(), term(), + {{Cipher :: string(), Salt :: binary()}, string()}) -> pem_entry(). +% +%% Description: Creates a pem entry that can be feed to pem_encode/1. +%%-------------------------------------------------------------------- +pem_entry_encode(Asn1Type, Entity) when is_atom(Asn1Type) -> + Der = der_encode(Asn1Type, Entity), + {Asn1Type, Der, not_encrypted}. +pem_entry_encode(Asn1Type, Entity, + {{Cipher, Salt}= CipherInfo, Password}) when is_atom(Asn1Type), + is_list(Cipher), + is_binary(Salt), + erlang:byte_size(Salt) == 8, + is_list(Password)-> + Der = der_encode(Asn1Type, Entity), + DecryptDer = pubkey_pem:cipher(Der, CipherInfo, Password), + {Asn1Type, DecryptDer, CipherInfo}. %%-------------------------------------------------------------------- -%% Function: decode_dhparams(DhParamInfo) -> -%% {ok, DhParams} | {error, Reason} -%% -%% DhParamsInfo = {Type, der_bin(), ChipherInfo} - as returned from -%% pem_to_der/[1,2] for DH parameters. -%% Type = dh_params -%% ChipherInfo = opaque() | no_encryption +-spec der_decode(asn1_type(), der_encoded()) -> term(). %% -%% Description: Decodes an asn1 der encoded DH parameters. +%% Description: Decodes a public key asn1 der encoded entity. %%-------------------------------------------------------------------- -decode_dhparams({dh_params, DerEncoded, not_encrypted}) -> - 'OTP-PUB-KEY':decode('DHParameter', DerEncoded). +der_decode(Asn1Type, Der) when is_atom(Asn1Type), is_binary(Der) -> + try + {ok, Decoded} = 'OTP-PUB-KEY':decode(Asn1Type, Der), + Decoded + catch + error:{badmatch, {error, _}} = Error -> + erlang:error(Error) + end. %%-------------------------------------------------------------------- -%% Function: decrypt_private(CipherText, Key) -> -%% decrypt_private(CipherText, Key, Options) -> PlainTex -%% decrypt_public(CipherText, Key) -> -%% decrypt_public(CipherText, Key, Options) -> PlainTex +-spec der_encode(asn1_type(), term()) -> der_encoded(). %% -%% CipherText = binary() -%% Key = rsa_key() -%% PlainText = binary() +%% Description: Encodes a public key entity with asn1 DER encoding. +%%-------------------------------------------------------------------- +der_encode(Asn1Type, Entity) when is_atom(Asn1Type) -> + try + {ok, Encoded} = 'OTP-PUB-KEY':encode(Asn1Type, Entity), + iolist_to_binary(Encoded) + catch + error:{badmatch, {error, _}} = Error -> + erlang:error(Error) + end. + +%%-------------------------------------------------------------------- +-spec pkix_decode_cert(der_encoded(), plain | otp) -> + #'Certificate'{} | #'OTPCertificate'{}. %% -%% Description: Decrypts <CipherText>. +%% Description: Decodes an asn1 der encoded pkix certificate. The otp +%% option will use the customized asn1 specification OTP-PKIX.asn1 for +%% decoding and also recursively decode most of the standard +%% extensions. +%% -------------------------------------------------------------------- +pkix_decode_cert(DerCert, plain) when is_binary(DerCert) -> + der_decode('Certificate', DerCert); +pkix_decode_cert(DerCert, otp) when is_binary(DerCert) -> + try + {ok, #'OTPCertificate'{}= Cert} = + pubkey_cert_records:decode_cert(DerCert), + Cert + catch + error:{badmatch, {error, _}} = Error -> + erlang:error(Error) + end. + +%%-------------------------------------------------------------------- +-spec pkix_encode(asn1_type(), term(), otp | plain) -> der_encoded(). +%% +%% Description: Der encodes a certificate or part of a certificate. +%% This function must be used for encoding certificates or parts of certificates +%% that are decoded with the otp format, whereas for the plain format this +%% function will only call der_encode/2. +%%-------------------------------------------------------------------- +pkix_encode(Asn1Type, Term, plain) when is_atom(Asn1Type) -> + der_encode(Asn1Type, Term); + +pkix_encode(Asn1Type, Term0, otp) when is_atom(Asn1Type) -> + Term = pubkey_cert_records:transform(Term0, encode), + der_encode(Asn1Type, Term). + +%%-------------------------------------------------------------------- +-spec decrypt_private(CipherText :: binary(), rsa_private_key()) -> + PlainText :: binary(). +-spec decrypt_private(CipherText :: binary(), rsa_private_key(), + public_crypt_options()) -> PlainText :: binary(). +%% +%% Description: Public key decryption using the private key. %%-------------------------------------------------------------------- decrypt_private(CipherText, Key) -> decrypt_private(CipherText, Key, []). -decrypt_private(CipherText, Key, Options) -> - Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), - pubkey_crypto:decrypt_private(CipherText, Key, Padding). -decrypt_public(CipherText, Key) -> - decrypt_public(CipherText, Key, []). -decrypt_public(CipherText, Key, Options) -> +decrypt_private(CipherText, + #'RSAPrivateKey'{modulus = N,publicExponent = E, + privateExponent = D}, + Options) when is_binary(CipherText), + is_list(Options) -> Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), - pubkey_crypto:decrypt_public(CipherText, Key, Padding). + crypto:rsa_private_decrypt(CipherText, + [crypto:mpint(E), crypto:mpint(N), + crypto:mpint(D)], Padding). %%-------------------------------------------------------------------- -%% Function: encrypt_public(PlainText, Key, Options) -> CipherText -%% encrypt_private(PlainText, Key, Options) -> CipherText -%% -%% PlainText = iolist() -%% Key = rsa_private_key() -%% CipherText = binary() +-spec decrypt_public(CipherText :: binary(), rsa_public_key()) -> + PlainText :: binary(). +-spec decrypt_public(CipherText :: binary(), rsa_public_key(), + public_crypt_options()) -> PlainText :: binary(). %% -%% Description: Encrypts <Plain> +%% Description: Public key decryption using the public key. %%-------------------------------------------------------------------- -encrypt_public(PlainText, Key) -> - encrypt_public(PlainText, Key, []). -encrypt_public(PlainText, Key, Options) -> - Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), - pubkey_crypto:encrypt_public(PlainText, Key, Padding). +decrypt_public(CipherText, Key) -> + decrypt_public(CipherText, Key, []). -encrypt_private(PlainText, Key) -> - encrypt_private(PlainText, Key, []). -encrypt_private(PlainText, Key, Options) -> - Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), - pubkey_crypto:encrypt_private(PlainText, Key, Padding). +decrypt_public(CipherText, #'RSAPublicKey'{modulus = N, publicExponent = E}, + Options) when is_binary(CipherText), is_list(Options) -> + decrypt_public(CipherText, N,E, Options); -%%-------------------------------------------------------------------- -%% Function: gen_key(Params) -> Keys -%% -%% Params = #'DomainParameters'{} - Currently only supported option -%% Keys = {PublicDHKey = integer(), PrivateDHKey = integer()} -%% -%% Description: Generates keys. Currently supports Diffie-Hellman keys. -%%-------------------------------------------------------------------- -gen_key(#'DHParameter'{prime = P, base = G}) when is_integer(P), - is_integer(G) -> - pubkey_crypto:gen_key(diffie_hellman, [P, G]). +decrypt_public(CipherText,#'RSAPrivateKey'{modulus = N, publicExponent = E}, + Options) when is_binary(CipherText), is_list(Options) -> + decrypt_public(CipherText, N,E, Options). %%-------------------------------------------------------------------- -%% Function: pem_to_der(CertSource) -> -%% pem_to_der(CertSource, Password) -> {ok, [Entry]} | -%% {error, Reason} -%% -%% CertSource = File | CertData -%% CertData = binary() -%% File = path() -%% Entry = {entry_type(), der_bin(), ChipherInfo} -%% ChipherInfo = opague() | no_encryption -%% der_bin() = binary() -%% entry_type() = cert | cert_req | rsa_private_key | dsa_private_key -%% dh_params +-spec encrypt_public(PlainText :: binary(), rsa_public_key()) -> + CipherText :: binary(). +-spec encrypt_public(PlainText :: binary(), rsa_public_key(), + public_crypt_options()) -> CipherText :: binary(). %% -%% Description: decode PEM binary data or a PEM file and return -%% entries as asn1 der encoded entities. Currently supported entry -%% types are certificates, certificate requests, rsa private keys and -%% dsa private keys. In the case of a key entry ChipherInfo will be -%% private keys and Diffie Hellam parameters .In the case of a key -%% entry ChipherInfo will be used by decode_private_key/2 if the key -%% is protected by a password. +%% Description: Public key encryption using the public key. %%-------------------------------------------------------------------- -pem_to_der(CertSource) -> - pem_to_der(CertSource, no_passwd). +encrypt_public(PlainText, Key) -> + encrypt_public(PlainText, Key, []). -pem_to_der(File, Password) when is_list(File) -> - pubkey_pem:read_file(File, Password); -pem_to_der(PemBin, Password) when is_binary(PemBin) -> - pubkey_pem:decode(PemBin, Password). +encrypt_public(PlainText, #'RSAPublicKey'{modulus=N,publicExponent=E}, + Options) when is_binary(PlainText), is_list(Options) -> + encrypt_public(PlainText, N,E, Options); -der_to_pem(File, TypeDerList) -> - pubkey_pem:write_file(File, TypeDerList). +encrypt_public(PlainText, #'RSAPrivateKey'{modulus=N,publicExponent=E}, + Options) when is_binary(PlainText), is_list(Options) -> + encrypt_public(PlainText, N,E, Options). %%-------------------------------------------------------------------- -%% Function: pkix_decode_cert(BerCert, Type) -> {ok, Cert} | {error, Reason} -%% -%% BerCert = binary() -%% Type = plain | otp -%% Cert = certificate() +-spec encrypt_private(PlainText :: binary(), rsa_private_key()) -> + CipherText :: binary(). +-spec encrypt_private(PlainText :: binary(), rsa_private_key(), + public_crypt_options()) -> CipherText :: binary(). %% -%% Description: Decodes an asn1 ber encoded pkix certificate. -%% otp - Uses OTP-PKIX.asn1 to decode known extensions and -%% enhance the signature field in #'Certificate'{} and '#TBSCertificate'{}. +%% Description: Public key encryption using the private key. %%-------------------------------------------------------------------- -pkix_decode_cert(BinCert, Type) -> - pubkey_cert_records:decode_cert(BinCert, Type). +encrypt_private(PlainText, Key) -> + encrypt_private(PlainText, Key, []). + +encrypt_private(PlainText, #'RSAPrivateKey'{modulus = N, + publicExponent = E, + privateExponent = D}, + Options) when is_binary(PlainText), is_list(Options) -> + Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), + crypto:rsa_private_encrypt(PlainText, [crypto:mpint(E), + crypto:mpint(N), + crypto:mpint(D)], Padding). %%-------------------------------------------------------------------- -%% Function: pkix_encode_cert(Cert) -> {ok, binary()} | {error, Reason} -%% -%% Cert = #'Certificate'{} +-spec sign(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type(), + rsa_private_key() | + dsa_private_key()) -> Signature :: binary(). %% -%% Description: Encodes a certificate record using asn1. +%% Description: Create digital signature. %%-------------------------------------------------------------------- -pkix_encode_cert(Cert) -> - pubkey_cert_records:encode_cert(Cert). +sign(PlainText, DigestType, #'RSAPrivateKey'{modulus = N, publicExponent = E, + privateExponent = D}) + when is_binary(PlainText), + DigestType == md5; + DigestType == sha -> + + crypto:rsa_sign(DigestType, sized_binary(PlainText), [crypto:mpint(E), + crypto:mpint(N), + crypto:mpint(D)]); + +sign(Digest, none, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) + when is_binary(Digest)-> + crypto:dss_sign(none, Digest, + [crypto:mpint(P), crypto:mpint(Q), + crypto:mpint(G), crypto:mpint(X)]); + +sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) + when is_binary(PlainText) -> + crypto:dss_sign(sized_binary(PlainText), + [crypto:mpint(P), crypto:mpint(Q), + crypto:mpint(G), crypto:mpint(X)]). + +%%-------------------------------------------------------------------- +-spec verify(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type(), + Signature :: binary(), rsa_public_key() + | dsa_public_key()) -> boolean(). +%% +%% Description: Verifies a digital signature. +%%-------------------------------------------------------------------- +verify(PlainText, DigestType, Signature, + #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) + when is_binary (PlainText), DigestType == sha; DigestType == md5 -> + crypto:rsa_verify(DigestType, + sized_binary(PlainText), + sized_binary(Signature), + [crypto:mpint(Exp), crypto:mpint(Mod)]); + +verify(Digest, none, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}}) + when is_integer(Key), is_binary(Digest), is_binary(Signature) -> + crypto:dss_verify(none, + Digest, + sized_binary(Signature), + [crypto:mpint(P), crypto:mpint(Q), + crypto:mpint(G), crypto:mpint(Key)]); +verify(PlainText, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}}) + when is_integer(Key), is_binary(PlainText), is_binary(Signature) -> + crypto:dss_verify(sized_binary(PlainText), + sized_binary(Signature), + [crypto:mpint(P), crypto:mpint(Q), + crypto:mpint(G), crypto:mpint(Key)]). %%-------------------------------------------------------------------- -%% Function: pkix_transform(CertPart, Op) -> TransformedCertPart +-spec pkix_sign(#'OTPTBSCertificate'{}, + rsa_private_key() | dsa_private_key()) -> der_encoded(). %% -%% CertPart = pkix part data -%% Op = encode | decode -%% -%% Description: Transform parts of a pkix certificate between 'plain' format -%% and the internal 'otp' format, see pkix_decode_cert/2. -%% Decode transforms from 'plain' to 'otp' and encode from 'otp' to 'plain' -%% format. +%% Description: Sign a pkix x.509 certificate. Returns the corresponding +%% der encoded 'Certificate'{} %%-------------------------------------------------------------------- -pkix_transform(CertPart, Op) -> - pubkey_cert_records:transform(CertPart, Op). +pkix_sign(#'OTPTBSCertificate'{signature = + #'SignatureAlgorithm'{algorithm = Alg} + = SigAlg} = TBSCert, Key) -> + + Msg = pkix_encode('OTPTBSCertificate', TBSCert, otp), + DigestType = pubkey_cert:digest_type(Alg), + Signature = sign(Msg, DigestType, Key), + Cert = #'OTPCertificate'{tbsCertificate= TBSCert, + signatureAlgorithm = SigAlg, + signature = {0, Signature} + }, + pkix_encode('OTPCertificate', Cert, otp). %%-------------------------------------------------------------------- -%% Function: pkix_path_validation(TrustedCert, CertChain, Options) -> -%% {ok, {{algorithm(), public_key(), public_key_params()} policy_tree()}} | -%% {error, Reason} +-spec pkix_verify(der_encoded(), rsa_public_key()| + dsa_public_key()) -> boolean(). %% -%% Description: Performs a bacis path validation according to RFC 3280. +%% Description: Verify pkix x.509 certificate signature. %%-------------------------------------------------------------------- -pkix_path_validation(TrustedCert, CertChain, Options) - when is_binary(TrustedCert) -> - {ok, OtpCert} = pkix_decode_cert(TrustedCert, otp), - pkix_path_validation(OtpCert, CertChain, Options); +pkix_verify(DerCert, {Key, #'Dss-Parms'{}} = DSAKey) + when is_binary(DerCert), is_integer(Key) -> + {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert), + verify(PlainText, DigestType, Signature, DSAKey); + +pkix_verify(DerCert, #'RSAPublicKey'{} = RSAKey) + when is_binary(DerCert) -> + {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert), + verify(PlainText, DigestType, Signature, RSAKey). -pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options) - when is_list(CertChain), is_list(Options) -> - MaxPathDefault = length(CertChain), - ValidationState = pubkey_cert:init_validation_state(TrustedCert, - MaxPathDefault, - Options), - Fun = proplists:get_value(validate_extensions_fun, Options, - fun(Extensions, State, _, AccError) -> - {Extensions, State, AccError} - end), - Verify = proplists:get_value(verify, Options, true), - path_validation(CertChain, ValidationState, Fun, Verify). %%-------------------------------------------------------------------- -%% Function: pkix_is_fixed_dh_cert(Cert) -> true | false +-spec pkix_is_issuer(Cert :: der_encoded()| #'OTPCertificate'{}, + IssuerCert :: der_encoded()| + #'OTPCertificate'{}) -> boolean(). %% -%% Description: Checks if a Certificate is a fixed Diffie-Hellman Cert +%% Description: Checks if <IssuerCert> issued <Cert>. %%-------------------------------------------------------------------- -pkix_is_fixed_dh_cert(#'OTPCertificate'{} = OTPCert) -> - pubkey_cert:is_fixed_dh_cert(OTPCert); -pkix_is_fixed_dh_cert(Cert) when is_binary(Cert) -> - {ok, OtpCert} = pkix_decode_cert(Cert, otp), - pkix_is_fixed_dh_cert(OtpCert). +pkix_is_issuer(Cert, IssuerCert) when is_binary(Cert) -> + OtpCert = pkix_decode_cert(Cert, otp), + pkix_is_issuer(OtpCert, IssuerCert); + +pkix_is_issuer(Cert, IssuerCert) when is_binary(IssuerCert) -> + OtpIssuerCert = pkix_decode_cert(IssuerCert, otp), + pkix_is_issuer(Cert, OtpIssuerCert); + +pkix_is_issuer(#'OTPCertificate'{tbsCertificate = TBSCert}, + #'OTPCertificate'{tbsCertificate = Candidate}) -> + pubkey_cert:is_issuer(TBSCert#'OTPTBSCertificate'.issuer, + Candidate#'OTPTBSCertificate'.subject). %%-------------------------------------------------------------------- -%% Function: pkix_is_self_signed(Cert) -> true | false +-spec pkix_is_self_signed(der_encoded()| #'OTPCertificate'{}) -> boolean(). %% %% Description: Checks if a Certificate is self signed. %%-------------------------------------------------------------------- pkix_is_self_signed(#'OTPCertificate'{} = OTPCert) -> pubkey_cert:is_self_signed(OTPCert); pkix_is_self_signed(Cert) when is_binary(Cert) -> - {ok, OtpCert} = pkix_decode_cert(Cert, otp), + OtpCert = pkix_decode_cert(Cert, otp), pkix_is_self_signed(OtpCert). - + %%-------------------------------------------------------------------- -%% Function: pkix_issuer_id(Cert) -> {ok, {SerialNr, Issuer}} | {error, Reason} -%% -%% Cert = asn1_der_encoded() | 'OTPCertificate'{} +-spec pkix_is_fixed_dh_cert(der_encoded()| #'OTPCertificate'{}) -> boolean(). %% +%% Description: Checks if a Certificate is a fixed Diffie-Hellman Cert. +%%-------------------------------------------------------------------- +pkix_is_fixed_dh_cert(#'OTPCertificate'{} = OTPCert) -> + pubkey_cert:is_fixed_dh_cert(OTPCert); +pkix_is_fixed_dh_cert(Cert) when is_binary(Cert) -> + OtpCert = pkix_decode_cert(Cert, otp), + pkix_is_fixed_dh_cert(OtpCert). + +%%-------------------------------------------------------------------- +-spec pkix_issuer_id(der_encoded()| #'OTPCertificate'{}, + IssuedBy :: self | other) -> + {ok, {SerialNr :: integer(), + Issuer :: {rdnSequence, + [#'AttributeTypeAndValue'{}]}}} + | {error, Reason :: term()}. +% %% Description: Returns the issuer id. %%-------------------------------------------------------------------- pkix_issuer_id(#'OTPCertificate'{} = OtpCert, self) -> @@ -265,115 +422,64 @@ pkix_issuer_id(#'OTPCertificate'{} = OtpCert, other) -> pubkey_cert:issuer_id(OtpCert, other); pkix_issuer_id(Cert, Signed) when is_binary(Cert) -> - {ok, OtpCert} = pkix_decode_cert(Cert, otp), + OtpCert = pkix_decode_cert(Cert, otp), pkix_issuer_id(OtpCert, Signed). %%-------------------------------------------------------------------- -%% Function: pkix_is_issuer(Cert, IssuerCert) -> true | false -%% -%% Cert = asn1_der_encoded() | 'OTPCertificate'{} -%% IssuerCert = asn1_der_encoded() | 'OTPCertificate'{} +-spec pkix_normalize_name({rdnSequence, + [#'AttributeTypeAndValue'{}]}) -> + {rdnSequence, + [#'AttributeTypeAndValue'{}]}. %% -%% Description: Checks if <IssuerCert> issued <Cert>. +%% Description: Normalizes a issuer name so that it can be easily +%% compared to another issuer name. %%-------------------------------------------------------------------- -pkix_is_issuer(Cert, IssuerCert) when is_binary(Cert) -> - {ok, OtpCert} = pkix_decode_cert(Cert, otp), - pkix_is_issuer(OtpCert, IssuerCert); - -pkix_is_issuer(Cert, IssuerCert) when is_binary(IssuerCert) -> - {ok, OtpIssuerCert} = pkix_decode_cert(IssuerCert, otp), - pkix_is_issuer(Cert, OtpIssuerCert); +pkix_normalize_name(Issuer) -> + pubkey_cert:normalize_general_name(Issuer). -pkix_is_issuer(#'OTPCertificate'{tbsCertificate = TBSCert}, - #'OTPCertificate'{tbsCertificate = Candidate}) -> - pubkey_cert:is_issuer(TBSCert#'OTPTBSCertificate'.issuer, - Candidate#'OTPTBSCertificate'.subject). - -%%-------------------------------------------------------------------- -%% Function: pkix_normalize_general_name(Issuer) -> -%% -%% Issuer = general_name() - see PKIX -%% -%% Description: Normalizes a general name so that it can be easily -%% compared to another genral name. +%%-------------------------------------------------------------------- +-spec pkix_path_validation(der_encoded()| #'OTPCertificate'{}, + CertChain :: [der_encoded()] , + Options :: list()) -> + {ok, {PublicKeyInfo :: term(), + PolicyTree :: term(), + [{bad_cert, Reason :: term()}]}} | + {error, {bad_cert, Reason :: term()}}. +%% Description: Performs a basic path validation according to RFC 5280. %%-------------------------------------------------------------------- -pkix_normalize_general_name(Issuer) -> - pubkey_cert:normalize_general_name(Issuer). +pkix_path_validation(TrustedCert, CertChain, Options) + when is_binary(TrustedCert) -> + OtpCert = pkix_decode_cert(TrustedCert, otp), + pkix_path_validation(OtpCert, CertChain, Options); + +pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options) + when is_list(CertChain), is_list(Options) -> + MaxPathDefault = length(CertChain), + ValidationState = pubkey_cert:init_validation_state(TrustedCert, + MaxPathDefault, + Options), + Fun = proplists:get_value(validate_extensions_fun, Options, + fun(Extensions, State, _, AccError) -> + {Extensions, State, AccError} + end), + Verify = proplists:get_value(verify, Options, true), + path_validation(CertChain, ValidationState, Fun, Verify). %%-------------------------------------------------------------------- -%% Function:sign(Msg, Key) -> {ok, Signature} -%% sign(Msg, Key, KeyParams) -> {ok, Signature} -%% -%% Msg = binary() | #'TBSCertificate'{} -%% Key = private_key() -%% KeyParams = key_params() -%% Signature = binary() -%% -%% Description: Signs plaintext Msg or #TBSCertificate{}, in the later -%% case a der encoded "#Certificate{}" will be returned. +%%% Internal functions %%-------------------------------------------------------------------- -sign(Msg, #'RSAPrivateKey'{} = Key) when is_binary(Msg) -> - pubkey_crypto:sign(Msg, Key); - -sign(Msg, #'DSAPrivateKey'{} = Key) when is_binary(Msg) -> - pubkey_crypto:sign(Msg, Key); -sign(#'OTPTBSCertificate'{signature = #'SignatureAlgorithm'{algorithm = Alg} - = SigAlg} = TBSCert, Key) -> - Msg = pubkey_cert_records:encode_tbs_cert(TBSCert), - DigestType = pubkey_cert:digest_type(Alg), - Signature = pubkey_crypto:sign(DigestType, Msg, Key), - Cert = #'OTPCertificate'{tbsCertificate= TBSCert, - signatureAlgorithm = SigAlg, - signature = {0, Signature} - }, - pkix_encode_cert(Cert). +encrypt_public(PlainText, N, E, Options)-> + Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), + crypto:rsa_public_encrypt(PlainText, [crypto:mpint(E),crypto:mpint(N)], + Padding). -sign(DigestType, Msg, Key) -> - pubkey_crypto:sign(DigestType, Msg, Key). +decrypt_public(CipherText, N,E, Options) -> + Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), + crypto:rsa_public_decrypt(CipherText,[crypto:mpint(E), crypto:mpint(N)], + Padding). -%%-------------------------------------------------------------------- -%% Function: verify_signature(PlainText, DigestType, Signature, Key) -> -%% verify_signature(PlainText, DigestType, -%% Signature, Key, KeyParams) -> -%% verify_signature(DerCert, Key, KeyParams) -> -%% -%% PlainText = binary() -%% DigestType = md5 | sha -%% DerCert = asn1_der_encoded() -%% Signature = binary() -%% Key = public_key() -%% KeyParams = key_params() -%% Verified = boolean() -%% -%% Description: Verifies the signature <Signature>. -%%-------------------------------------------------------------------- -verify_signature(PlainText, DigestType, Signature, #'RSAPublicKey'{} = Key) - when is_binary(PlainText), is_binary(Signature), DigestType == sha; - DigestType == md5 -> - pubkey_crypto:verify(DigestType, PlainText, Signature, Key, undefined). - -verify_signature(PlainText, DigestType, Signature, #'RSAPublicKey'{} = Key, - KeyParams) - when is_binary(PlainText), is_binary(Signature), DigestType == sha; - DigestType == md5 -> - pubkey_crypto:verify(DigestType, PlainText, Signature, Key, KeyParams); -verify_signature(PlainText, sha, Signature, Key, #'Dss-Parms'{} = KeyParams) - when is_binary(PlainText), is_binary(Signature), is_integer(Key) -> - pubkey_crypto:verify(sha, PlainText, Signature, Key, KeyParams); -verify_signature(Hash, none, Signature, Key, KeyParams) -> - pubkey_crypto:verify(none, Hash, Signature, Key, KeyParams). - -verify_signature(DerCert, Key, #'Dss-Parms'{} = KeyParams) - when is_binary(DerCert), is_integer(Key) -> - pubkey_cert:verify_signature(DerCert, Key, KeyParams); -verify_signature(DerCert, #'RSAPublicKey'{} = Key, KeyParams) - when is_binary(DerCert) -> - pubkey_cert:verify_signature(DerCert, Key, KeyParams). -%%-------------------------------------------------------------------- -%%% Internal functions -%%-------------------------------------------------------------------- path_validation([], #path_validation_state{working_public_key_algorithm = Algorithm, working_public_key = @@ -423,7 +529,7 @@ validate(DerCert, #path_validation_state{working_issuer_name = Issuer, user_state = UserState0, acc_errors = AccErr0} = ValidationState0, ValidateExtensionFun, Verify) -> - {ok, OtpCert} = pkix_decode_cert(DerCert, otp), + OtpCert = pkix_decode_cert(DerCert, otp), %% All validate functions will throw {bad_cert, Reason} if they %% fail and Verify = true if Verify = false errors %% will be accumulated in the validationstate @@ -456,3 +562,26 @@ validate(DerCert, #path_validation_state{working_issuer_name = Issuer, ValidationState1#path_validation_state{user_state = UserState, acc_errors = AccErr}, pubkey_cert:prepare_for_next_cert(OtpCert, ValidationState). + +sized_binary(Binary) when is_binary(Binary) -> + Size = size(Binary), + <<?UINT32(Size), Binary/binary>>; +sized_binary(List) -> + sized_binary(list_to_binary(List)). + +%%-------------------------------------------------------------------- +%%% Deprecated functions +%%-------------------------------------------------------------------- +pem_to_der(CertSource) -> + {ok, Bin} = file:read_file(CertSource), + pubkey_pem:decode(Bin). + +decode_private_key(KeyInfo) -> + decode_private_key(KeyInfo, no_passwd). + +decode_private_key(KeyInfo = {'RSAPrivateKey', _, _}, Password) -> + DerEncoded = pubkey_pem:decode_key(KeyInfo, Password), + 'OTP-PUB-KEY':decode('RSAPrivateKey', DerEncoded); +decode_private_key(KeyInfo = {'DSAPrivateKey', _, _}, Password) -> + DerEncoded = pubkey_pem:decode_key(KeyInfo, Password), + 'OTP-PUB-KEY':decode('DSAPrivateKey', DerEncoded). diff --git a/lib/public_key/test/pkey_test.erl b/lib/public_key/test/pkey_test.erl index 4cf20f0174..deb4defd29 100644 --- a/lib/public_key/test/pkey_test.erl +++ b/lib/public_key/test/pkey_test.erl @@ -34,7 +34,7 @@ %% version 3 %% subject [] list of the following content %% {name, Name} -%% {email, Email} +%% {email, Email} %% {city, City} %% {state, State} %% {org, Org} @@ -56,7 +56,7 @@ make_cert(Opts) -> SubjectPrivateKey = get_key(Opts), {TBSCert, IssuerKey} = make_tbs(SubjectPrivateKey, Opts), - Cert = public_key:sign(TBSCert, IssuerKey), + Cert = public_key:pkix_sign(TBSCert, IssuerKey), true = verify_signature(Cert, IssuerKey, undef), %% verify that the keys where ok {Cert, encode_key(SubjectPrivateKey)}. @@ -66,8 +66,9 @@ make_cert(Opts) -> %% @end %%-------------------------------------------------------------------- write_pem(Dir, FileName, {Cert, Key = {_,_,not_encrypted}}) when is_binary(Cert) -> - ok = public_key:der_to_pem(filename:join(Dir, FileName ++ ".pem"), [{cert, Cert, not_encrypted}]), - ok = public_key:der_to_pem(filename:join(Dir, FileName ++ "_key.pem"), [Key]). + ok = der_to_pem(filename:join(Dir, FileName ++ ".pem"), + [{'Certificate', Cert, not_encrypted}]), + ok = der_to_pem(filename:join(Dir, FileName ++ "_key.pem"), [Key]). %%-------------------------------------------------------------------- %% @doc Creates a rsa key (OBS: for testing only) @@ -94,18 +95,14 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) -> %% @spec (::binary(), ::tuple()) -> ::boolean() %% @end %%-------------------------------------------------------------------- -verify_signature(DerEncodedCert, DerKey, KeyParams) -> +verify_signature(DerEncodedCert, DerKey, _KeyParams) -> Key = decode_key(DerKey), case Key of #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} -> - public_key:verify_signature(DerEncodedCert, - #'RSAPublicKey'{modulus=Mod, publicExponent=Exp}, - 'NULL'); + public_key:pkix_verify(DerEncodedCert, + #'RSAPublicKey'{modulus=Mod, publicExponent=Exp}); #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} -> - public_key:verify_signature(DerEncodedCert, Y, #'Dss-Parms'{p=P, q=Q, g=G}); - - _ -> - public_key:verify_signature(DerEncodedCert, Key, KeyParams) + public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}) end. %%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -132,19 +129,18 @@ decode_key(#'RSAPrivateKey'{} = Key,_) -> Key; decode_key(#'DSAPrivateKey'{} = Key,_) -> Key; -decode_key(Der = {_,_,_}, Pw) -> - {ok, Key} = public_key:decode_private_key(Der, Pw), - Key; -decode_key(FileOrDer, Pw) -> - {ok, [KeyInfo]} = public_key:pem_to_der(FileOrDer), +decode_key(PemEntry = {_,_,_}, Pw) -> + public_key:pem_entry_decode(PemEntry, Pw); +decode_key(PemBin, Pw) -> + [KeyInfo] = public_key:pem_decode(PemBin), decode_key(KeyInfo, Pw). encode_key(Key = #'RSAPrivateKey'{}) -> {ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key), - {rsa_private_key, list_to_binary(Der), not_encrypted}; + {'RSAPrivateKey', list_to_binary(Der), not_encrypted}; encode_key(Key = #'DSAPrivateKey'{}) -> {ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key), - {dsa_private_key, list_to_binary(Der), not_encrypted}. + {'DSAPrivateKey', list_to_binary(Der), not_encrypted}. make_tbs(SubjectKey, Opts) -> Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))), @@ -178,7 +174,7 @@ issuer(Opts, SubjectKey) -> end. issuer_der(Issuer) -> - {ok, Decoded} = public_key:pkix_decode_cert(Issuer, otp), + Decoded = public_key:pkix_decode_cert(Issuer, otp), #'OTPCertificate'{tbsCertificate=Tbs} = Decoded, #'OTPTBSCertificate'{subject=Subject} = Tbs, Subject. @@ -271,7 +267,7 @@ publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) -> #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}. validity(Opts) -> - DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1), + DefFrom0 = date(), DefTo0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())+7), {DefFrom, DefTo} = proplists:get_value(validity, Opts, {DefFrom0, DefTo0}), Format = fun({Y,M,D}) -> lists:flatten(io_lib:format("~w~2..0w~2..0w000000Z",[Y,M,D])) end, @@ -410,3 +406,11 @@ extended_gcd(A, B) -> {X, Y} = extended_gcd(B, N), {Y, X-Y*(A div B)} end. + +pem_to_der(File) -> + {ok, PemBin} = file:read_file(File), + public_key:pem_decode(PemBin). + +der_to_pem(File, Entries) -> + PemBin = public_key:pem_encode(Entries), + file:write_file(File, PemBin). diff --git a/lib/public_key/test/pkits_SUITE.erl b/lib/public_key/test/pkits_SUITE.erl index 5d58b39e26..cd7b2d77db 100644 --- a/lib/public_key/test/pkits_SUITE.erl +++ b/lib/public_key/test/pkits_SUITE.erl @@ -187,9 +187,9 @@ run([],_) -> ok. read_certs(Test) -> File = test_file(Test), %% io:format("Read ~p ",[File]), - {ok, Ders} = public_key:pem_to_der(File), + Ders = pkey_test:pem_to_der(File), %% io:format("Ders ~p ~n",[length(Ders)]), - [Cert || {cert,Cert,not_encrypted} <- Ders]. + [Cert || {'Certificate', Cert, not_encrypted} <- Ders]. test_file(Test) -> file(?CONV, lists:append(string:tokens(Test, " -")) ++ ".pem"). diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index dc1015969a..1d32e989a9 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -101,13 +101,12 @@ all(doc) -> all(suite) -> [app, - dh, - pem_to_der, - decode_private_key, + pk_decode_encode, encrypt_decrypt, sign_verify, pkix, - pkix_path_validation + pkix_path_validation, + deprecated ]. %% Test cases starts here. @@ -120,78 +119,93 @@ app(suite) -> app(Config) when is_list(Config) -> ok = test_server:app_test(public_key). -dh(doc) -> - "Test diffie-hellman functions file is ok"; -dh(suite) -> +pk_decode_encode(doc) -> + ["Tests pem_decode/1, pem_encode/1, " + "der_decode/2, der_encode/2, " + "pem_entry_decode/1, pem_entry_decode/2," + "pem_entry_encode/2, pem_entry_encode/3."]; + +pk_decode_encode(suite) -> []; -dh(Config) when is_list(Config) -> +pk_decode_encode(Config) when is_list(Config) -> Datadir = ?config(data_dir, Config), - {ok,[DerDHparams = {dh_params, _, _}]} = - public_key:pem_to_der(filename:join(Datadir, "dh.pem")), - {ok, DHps = #'DHParameter'{prime=P,base=G}} = public_key:decode_dhparams(DerDHparams), - DHKeys = {Private,_Public} = public_key:gen_key(DHps), - test_server:format("DHparams = ~p~nDH Keys~p~n", [DHps, DHKeys]), - {_Private,_Public2} = pubkey_crypto:gen_key(diffie_hellman, [crypto:erlint(Private), P, G]), - ok. + + [{'DSAPrivateKey', DerDSAKey, not_encrypted} = Entry0 ] = + pkey_test:pem_to_der(filename:join(Datadir, "dsa.pem")), + + DSAKey = public_key:der_decode('DSAPrivateKey', DerDSAKey), + + DSAKey = public_key:pem_entry_decode(Entry0), + + [{'RSAPrivateKey', DerRSAKey, not_encrypted} = Entry1 ] = + pkey_test:pem_to_der(filename:join(Datadir, "client_key.pem")), + + RSAKey0 = public_key:der_decode('RSAPrivateKey', DerRSAKey), + + RSAKey0 = public_key:pem_entry_decode(Entry1), + + [{'RSAPrivateKey', _, {_,_}} = Entry2] = + pkey_test:pem_to_der(filename:join(Datadir, "rsa.pem")), + true = check_entry_type(public_key:pem_entry_decode(Entry2, "abcd1234"), + 'RSAPrivateKey'), -pem_to_der(doc) -> - ["Check that supported PEM files are decoded into the expected entry type"]; -pem_to_der(suite) -> - []; -pem_to_der(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), - {ok,DSAKey =[{dsa_private_key, _, not_encrypted}]} = - public_key:pem_to_der(filename:join(Datadir, "dsa.pem")), - {ok,[{rsa_private_key, _, _}]} = - public_key:pem_to_der(filename:join(Datadir, "client_key.pem")), - {ok, [{rsa_private_key, _, _}]} = - public_key:pem_to_der(filename:join(Datadir, "rsa.pem")), - {ok,[{rsa_private_key, _, _}]} = - public_key:pem_to_der(filename:join(Datadir, "rsa.pem"), "abcd1234"), - {ok, Bin0} = file:read_file(filename:join(Datadir, "rsa.pem")), - {ok, [{rsa_private_key, _, _}]} = public_key:pem_to_der(Bin0, "abcd1234"), - - {ok,[{dh_params, _, _}]} = - public_key:pem_to_der(filename:join(Datadir, "dh.pem")), - {ok,[{cert, _, not_encrypted}]} = - public_key:pem_to_der(filename:join(Datadir, "client_cert.pem")), - {ok,[{cert_req, _, _}]} = - public_key:pem_to_der(filename:join(Datadir, "req.pem")), - {ok, Certs = [{cert, _, _}, {cert, _, _}]} = - public_key:pem_to_der(filename:join(Datadir, "cacerts.pem")), - - {ok, Bin1} = file:read_file(filename:join(Datadir, "cacerts.pem")), - {ok, [{cert, _, _}, {cert, _, _}]} = public_key:pem_to_der(Bin1), - - ok = public_key:der_to_pem(filename:join(Datadir, "wcacerts.pem"), Certs), - ok = public_key:der_to_pem(filename:join(Datadir, "wdsa.pem"), DSAKey), + Salt0 = crypto:rand_bytes(8), + Entry3 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey0, + {{"DES-EDE3-CBC", Salt0}, "1234abcd"}), + + RSAKey0 = public_key:pem_entry_decode(Entry3,"1234abcd"), - {ok, Certs} = public_key:pem_to_der(filename:join(Datadir, "wcacerts.pem")), - {ok, DSAKey} = public_key:pem_to_der(filename:join(Datadir, "wdsa.pem")), + Des3KeyFile = filename:join(Datadir, "des3_client_key.pem"), - ok. -%%-------------------------------------------------------------------- -decode_private_key(doc) -> - ["Check that private keys are decode to the expected key type."]; -decode_private_key(suite) -> - []; -decode_private_key(Config) when is_list(Config) -> - Datadir = ?config(data_dir, Config), - {ok,[DsaKey = {dsa_private_key, _DsaKey, _}]} = - public_key:pem_to_der(filename:join(Datadir, "dsa.pem")), - {ok,[RsaKey = {rsa_private_key, _RsaKey,_}]} = - public_key:pem_to_der(filename:join(Datadir, "client_key.pem")), - {ok,[ProtectedRsaKey1 = {rsa_private_key, _ProtectedRsaKey1,_}]} = - public_key:pem_to_der(filename:join(Datadir, "rsa.pem"), "abcd1234"), - {ok,[ProtectedRsaKey2 = {rsa_private_key, _ProtectedRsaKey2,_}]} = - public_key:pem_to_der(filename:join(Datadir, "rsa.pem")), + pkey_test:der_to_pem(Des3KeyFile, [Entry3]), - {ok, #'DSAPrivateKey'{}} = public_key:decode_private_key(DsaKey), - {ok, #'RSAPrivateKey'{}} = public_key:decode_private_key(RsaKey), - {ok, #'RSAPrivateKey'{}} = public_key:decode_private_key(ProtectedRsaKey1), - {ok, #'RSAPrivateKey'{}} = public_key:decode_private_key(ProtectedRsaKey2, "abcd1234"), + [{'RSAPrivateKey', _, {"DES-EDE3-CBC", Salt0}}] = pkey_test:pem_to_der(Des3KeyFile), + + Salt1 = crypto:rand_bytes(8), + Entry4 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey0, + {{"DES-CBC", Salt1}, "4567efgh"}), + + + DesKeyFile = filename:join(Datadir, "des_client_key.pem"), + + pkey_test:der_to_pem(DesKeyFile, [Entry4]), + + [{'RSAPrivateKey', _, {"DES-CBC", Salt1}} =Entry5] = pkey_test:pem_to_der(DesKeyFile), + + + true = check_entry_type(public_key:pem_entry_decode(Entry5, "4567efgh"), + 'RSAPrivateKey'), + + [{'DHParameter', DerDH, not_encrypted} = Entry6] = + pkey_test:pem_to_der(filename:join(Datadir, "dh.pem")), + + pkey_test:der_to_pem(filename:join(Datadir, "new_dh.pem"), [Entry6]), + + DHParameter = public_key:der_decode('DHParameter', DerDH), + DHParameter = public_key:pem_entry_decode(Entry6), + + Entry6 = public_key:pem_entry_encode('DHParameter', DHParameter), + + [{'Certificate', DerCert, not_encrypted} = Entry7] = + pkey_test:pem_to_der(filename:join(Datadir, "client_cert.pem")), + + Cert = public_key:der_decode('Certificate', DerCert), + Cert = public_key:pem_entry_decode(Entry7), + + CertEntries = [{'Certificate', _, not_encrypted} = CertEntry0, + {'Certificate', _, not_encrypted} = CertEntry1] = + pkey_test:pem_to_der(filename:join(Datadir, "cacerts.pem")), + + ok = pkey_test:der_to_pem(filename:join(Datadir, "wcacerts.pem"), CertEntries), + ok = pkey_test:der_to_pem(filename:join(Datadir, "wdsa.pem"), [Entry0]), + + NewCertEntries = pkey_test:pem_to_der(filename:join(Datadir, "wcacerts.pem")), + true = lists:member(CertEntry0, NewCertEntries), + true = lists:member(CertEntry1, NewCertEntries), + [Entry0] = pkey_test:pem_to_der(filename:join(Datadir, "wdsa.pem")), ok. + %%-------------------------------------------------------------------- encrypt_decrypt(doc) -> [""]; @@ -220,68 +234,80 @@ sign_verify(suite) -> sign_verify(Config) when is_list(Config) -> %% Make cert signs and validates the signature using RSA and DSA Ca = {_, CaKey} = pkey_test:make_cert([]), - {ok, PrivateRSA = #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp}} = - public_key:decode_private_key(CaKey), + PrivateRSA = #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} = + public_key:pem_entry_decode(CaKey), CertInfo = {Cert1,CertKey1} = pkey_test:make_cert([{key, dsa}, {issuer, Ca}]), PublicRSA = #'RSAPublicKey'{modulus=Mod, publicExponent=Exp}, - true = public_key:verify_signature(Cert1, PublicRSA, undefined), + true = public_key:pkix_verify(Cert1, PublicRSA), {Cert2,_CertKey} = pkey_test:make_cert([{issuer, CertInfo}]), - {ok, #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y, x=_X}} = - public_key:decode_private_key(CertKey1), - true = public_key:verify_signature(Cert2, Y, #'Dss-Parms'{p=P, q=Q, g=G}), + #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y, x=_X} = + public_key:pem_entry_decode(CertKey1), + true = public_key:pkix_verify(Cert2, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}), %% RSA sign Msg0 = lists:duplicate(5, "Foo bar 100"), Msg = list_to_binary(Msg0), - RSASign = public_key:sign(sha, Msg0, PrivateRSA), - RSASign = public_key:sign(Msg, PrivateRSA), - true = public_key:verify_signature(Msg, sha, RSASign, PublicRSA), - false = public_key:verify_signature(<<1:8, Msg/binary>>, sha, RSASign, PublicRSA), - false = public_key:verify_signature(Msg, sha, <<1:8, RSASign/binary>>, PublicRSA), - RSASign = public_key:sign(sha, Msg, PrivateRSA), - - RSASign1 = public_key:sign(md5, Msg, PrivateRSA), - true = public_key:verify_signature(Msg, md5, RSASign1, PublicRSA), + + RSASign = public_key:sign(Msg0, sha, PrivateRSA), + RSASign = public_key:sign(Msg, sha, PrivateRSA), + true = public_key:verify(Msg, sha, RSASign, PublicRSA), + false = public_key:verify(<<1:8, Msg/binary>>, sha, RSASign, PublicRSA), + false = public_key:verify(Msg, sha, <<1:8, RSASign/binary>>, PublicRSA), + + RSASign1 = public_key:sign(Msg, md5, PrivateRSA), + true = public_key:verify(Msg, md5, RSASign1, PublicRSA), %% DSA sign Datadir = ?config(data_dir, Config), - {ok,[DsaKey = {dsa_private_key, _, _}]} = - public_key:pem_to_der(filename:join(Datadir, "dsa.pem")), - {ok, DSAPrivateKey} = public_key:decode_private_key(DsaKey), + [DsaKey = {'DSAPrivateKey', _, _}] = + pkey_test:pem_to_der(filename:join(Datadir, "dsa.pem")), + DSAPrivateKey = public_key:pem_entry_decode(DsaKey), #'DSAPrivateKey'{p=P1, q=Q1, g=G1, y=Y1, x=_X1} = DSAPrivateKey, - DSASign = public_key:sign(Msg, DSAPrivateKey), + DSASign = public_key:sign(Msg, sha, DSAPrivateKey), DSAPublicKey = Y1, DSAParams = #'Dss-Parms'{p=P1, q=Q1, g=G1}, - true = public_key:verify_signature(Msg, sha, DSASign, DSAPublicKey, DSAParams), - false = public_key:verify_signature(<<1:8, Msg/binary>>, sha, DSASign, DSAPublicKey, DSAParams), - false = public_key:verify_signature(Msg, sha, <<1:8, DSASign/binary>>, DSAPublicKey, DSAParams), + true = public_key:verify(Msg, sha, DSASign, {DSAPublicKey, DSAParams}), + false = public_key:verify(<<1:8, Msg/binary>>, sha, DSASign, + {DSAPublicKey, DSAParams}), + false = public_key:verify(Msg, sha, <<1:8, DSASign/binary>>, + {DSAPublicKey, DSAParams}), + + Digest = crypto:sha(Msg), + DigestSign = public_key:sign(Digest, none, DSAPrivateKey), + true = public_key:verify(Digest, none, DigestSign, {DSAPublicKey, DSAParams}), + <<_:8, RestDigest/binary>> = Digest, + false = public_key:verify(<<1:8, RestDigest/binary>>, none, DigestSign, + {DSAPublicKey, DSAParams}), + false = public_key:verify(Digest, none, <<1:8, DigestSign/binary>>, + {DSAPublicKey, DSAParams}), ok. - +%%-------------------------------------------------------------------- pkix(doc) -> "Misc pkix tests not covered elsewhere"; pkix(suite) -> []; pkix(Config) when is_list(Config) -> Datadir = ?config(data_dir, Config), - {ok,Certs0} = public_key:pem_to_der(filename:join(Datadir, "cacerts.pem")), - {ok,Certs1} = public_key:pem_to_der(filename:join(Datadir, "client_cert.pem")), - TestTransform = fun({cert, CertDer, not_encrypted}) -> - {ok, PlainCert} = public_key:pkix_decode_cert(CertDer, plain), - {ok, OtpCert} = public_key:pkix_decode_cert(CertDer, otp), - CertDer = public_key:pkix_encode_cert(OtpCert), - CertDer = public_key:pkix_encode_cert(PlainCert), - - OTPSubj = (OtpCert#'OTPCertificate'.tbsCertificate)#'OTPTBSCertificate'.subject, - Subj = public_key:pkix_transform(OTPSubj, encode), - {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj), - Subj2 = (PlainCert#'Certificate'.tbsCertificate)#'TBSCertificate'.subject, - {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj2), - OTPSubj = public_key:pkix_transform(Subj2, decode), + Certs0 = pkey_test:pem_to_der(filename:join(Datadir, "cacerts.pem")), + Certs1 = pkey_test:pem_to_der(filename:join(Datadir, "client_cert.pem")), + TestTransform = fun({'Certificate', CertDer, not_encrypted}) -> + PlainCert = public_key:pkix_decode_cert(CertDer, plain), + OtpCert = public_key:pkix_decode_cert(CertDer, otp), + CertDer = + public_key:pkix_encode('OTPCertificate', OtpCert, otp), + CertDer = + public_key:pkix_encode('Certificate', PlainCert, plain), + OTPTBS = OtpCert#'OTPCertificate'.tbsCertificate, + OTPSubj = OTPTBS#'OTPTBSCertificate'.subject, + DNEncoded = public_key:pkix_encode('Name', OTPSubj, otp), + PlainTBS = PlainCert#'Certificate'.tbsCertificate, + Subj2 = PlainTBS#'TBSCertificate'.subject, + DNEncoded = public_key:pkix_encode('Name', Subj2, plain), false = public_key:pkix_is_fixed_dh_cert(CertDer) end, @@ -290,19 +316,24 @@ pkix(Config) when is_list(Config) -> true = public_key:pkix_is_self_signed(element(2,hd(Certs0))), false = public_key:pkix_is_self_signed(element(2,hd(Certs1))), - CaIds = [element(2, public_key:pkix_issuer_id(Cert, self)) || {cert, Cert, _} <- Certs0], - {ok, IssuerId = {_, IssuerName}} = public_key:pkix_issuer_id(element(2,hd(Certs1)), other), + CaIds = [element(2, public_key:pkix_issuer_id(Cert, self)) || + {'Certificate', Cert, _} <- Certs0], + {ok, IssuerId = {_, _IssuerName}} = + public_key:pkix_issuer_id(element(2,hd(Certs1)), other), + true = lists:member(IssuerId, CaIds), %% Should be normalized allready - TestStr = {rdnSequence, [[{'AttributeTypeAndValue', {2,5,4,3},{printableString,"ERLANGCA"}}], - [{'AttributeTypeAndValue', {2,5,4,3},{printableString," erlang ca "}}]]}, - VerifyStr = {rdnSequence, [[{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlang ca"}}], - [{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlangca"}}]]}, - VerifyStr = public_key:pkix_normalize_general_name(TestStr), + TestStr = {rdnSequence, + [[{'AttributeTypeAndValue', {2,5,4,3},{printableString,"ERLANGCA"}}], + [{'AttributeTypeAndValue', {2,5,4,3},{printableString," erlang ca "}}]]}, + VerifyStr = {rdnSequence, + [[{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlang ca"}}], + [{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlangca"}}]]}, + VerifyStr = public_key:pkix_normalize_name(TestStr), ok. - +%%-------------------------------------------------------------------- pkix_path_validation(doc) -> "Misc pkix tests not covered elsewhere"; pkix_path_validation(suite) -> @@ -323,23 +354,56 @@ pkix_path_validation(Config) when is_list(Config) -> ok = pkey_test:write_pem("./", "public_key_cacert", CaK), CertK1 = {Cert1, _} = pkey_test:make_cert([{issuer, CaK}]), - CertK2 = {Cert2,_} = pkey_test:make_cert([{issuer, CertK1}, {digest, md5}, {extensions, false}]), + CertK2 = {Cert2,_} = pkey_test:make_cert([{issuer, CertK1}, + {digest, md5}, {extensions, false}]), ok = pkey_test:write_pem("./", "public_key_cert", CertK2), {ok, _} = public_key:pkix_path_validation(Trusted, [Cert1], []), - {error, {bad_cert,invalid_issuer}} = public_key:pkix_path_validation(Trusted, [Cert2], []), - %%{error, {bad_cert,invalid_issuer}} = public_key:pkix_path_validation(Trusted, [Cert2], [{verify,false}]), + {error, {bad_cert,invalid_issuer}} = + public_key:pkix_path_validation(Trusted, [Cert2], []), {ok, _} = public_key:pkix_path_validation(Trusted, [Cert1, Cert2], []), {error, issuer_not_found} = public_key:pkix_issuer_id(Cert2, other), - CertK3 = {Cert3,_} = pkey_test:make_cert([{issuer, CertK1}, {extensions, [{basic_constraints, false}]}]), + CertK3 = {Cert3,_} = pkey_test:make_cert([{issuer, CertK1}, + {extensions, [{basic_constraints, false}]}]), {Cert4,_} = pkey_test:make_cert([{issuer, CertK3}]), {error, E={bad_cert,missing_basic_constraint}} = public_key:pkix_path_validation(Trusted, [Cert1, Cert3,Cert4], []), - {ok, {_,_,[E]}} = public_key:pkix_path_validation(Trusted, [Cert1, Cert3,Cert4], [{verify,false}]), + {ok, {_,_,[E]}} = public_key:pkix_path_validation(Trusted, [Cert1, Cert3,Cert4], + [{verify,false}]), + ok. - % test_server:format("PV ~p ~n", [Result]), +%%-------------------------------------------------------------------- +deprecated(doc) -> + ["Check deprecated functions."]; +deprecated(suite) -> + []; +deprecated(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + [DsaKey = {'DSAPrivateKey', _DsaKey, _}] = + public_key:pem_to_der(filename:join(Datadir, "dsa.pem")), + [RsaKey = {'RSAPrivateKey', _RsaKey,_}] = + public_key:pem_to_der(filename:join(Datadir, "client_key.pem")), + [ProtectedRsaKey = {'RSAPrivateKey', _ProtectedRsaKey,_}] = + public_key:pem_to_der(filename:join(Datadir, "rsa.pem")), + + {ok, #'DSAPrivateKey'{}} = public_key:decode_private_key(DsaKey), + {ok, #'RSAPrivateKey'{}} = public_key:decode_private_key(RsaKey), + {ok, #'RSAPrivateKey'{}} = public_key:decode_private_key(ProtectedRsaKey, "abcd1234"), ok. + +%%-------------------------------------------------------------------- + +check_entry_type(#'DSAPrivateKey'{}, 'DSAPrivateKey') -> + true; +check_entry_type(#'RSAPrivateKey'{}, 'RSAPrivateKey') -> + true; +check_entry_type(#'DHParameter'{}, 'DHParameter') -> + true; +check_entry_type(#'Certificate'{}, 'Certificate') -> + true; +check_entry_type(_,_) -> + false. diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk index 4b3071a85b..f70209d891 100644 --- a/lib/public_key/vsn.mk +++ b/lib/public_key/vsn.mk @@ -1,11 +1 @@ -PUBLIC_KEY_VSN = 0.7 - -TICKETS = OTP-8626 OTP-8649 - -#TICKETS_0.6 = OTP-7046 \ -# OTP-8553 -#TICKETS_0.5 = OTP-8372 -#TICKETS_0.4 = OTP-8250 -#TICKETS_0.3 = OTP-8100 OTP-8142 -#TICKETS_0.2 = OTP-7860 -#TICKETS_0.1 = OTP-7637
\ No newline at end of file +PUBLIC_KEY_VSN = 0.8 diff --git a/lib/reltool/vsn.mk b/lib/reltool/vsn.mk index f23a7e84a2..7bee91d428 100644 --- a/lib/reltool/vsn.mk +++ b/lib/reltool/vsn.mk @@ -17,12 +17,3 @@ # %CopyrightEnd% RELTOOL_VSN = 0.5.4 - -TICKETS = OTP-8521 OTP-8590 -TICKETS_0_5_3 = OTP-8057 -TICKETS_0_5_2 = OTP-8254 -TICKETS_0_5_1 = OTP-8199 -TICKETS_0_5 = OTP-7949 -TICKETS_0_2_2 = OTP-7999 -TICKETS_2_2_1 = OTP-7840 -TICKETS_0_2 = OTP-7805 diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml index 3f4954cfbd..d5d6605b64 100644 --- a/lib/snmp/doc/src/notes.xml +++ b/lib/snmp/doc/src/notes.xml @@ -13,12 +13,12 @@ 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. - + </legalnotice> <title>SNMP Release Notes</title> @@ -33,6 +33,34 @@ </header> <section> + <title>SNMP Development Toolkit 4.17.1</title> + <p>Version 4.17.1 supports code replacement in runtime from/to + version 4.17, 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>When the function FilterMod:accept_recv/2 + returned false the SNMP agent stopped collecting messages from UDP.</p> + <p>Own Id: OTP-8761</p> + </item> + </list> + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.17.1 --> + + + <section> <title>SNMP Development Toolkit 4.17</title> <p>Version 4.17 supports code replacement in runtime from/to version 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p> diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl index 3a91cf4033..97a7a63dee 100644 --- a/lib/snmp/src/agent/snmpa_net_if.erl +++ b/lib/snmp/src/agent/snmpa_net_if.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 2004-2010. 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% %% -module(snmpa_net_if). @@ -478,12 +478,13 @@ update_req_counter_outgoing(#state{limit = Limit, rcnt = RCnt} = S, S#state{rcnt = NewRCnt}. -maybe_handle_recv(#state{filter = FilterMod} = S, +maybe_handle_recv(#state{usock = Sock, filter = FilterMod} = S, Ip, Port, Packet) -> case (catch FilterMod:accept_recv(Ip, Port)) of false -> %% Drop the received packet inc(netIfMsgInDrops), + active_once(Sock), S; _ -> handle_recv(S, Ip, Port, Packet) diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src index 9ad16ffad2..2bd26e11db 100644 --- a/lib/snmp/src/app/snmp.appup.src +++ b/lib/snmp/src/app/snmp.appup.src @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 1999-2010. 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% %% @@ -22,6 +22,11 @@ %% ----- U p g r a d e ------------------------------------------------------- [ + {"4.17", + [ + {load_module, snmpa_net_if, soft_purge, soft_purge, []} + ] + }, {"4.16.2", [ {load_module, snmp_log, soft_purge, soft_purge, []}, @@ -29,6 +34,7 @@ {load_module, snmpa_mpd, soft_purge, soft_purge, [snmpa_usm]}, {load_module, snmpa_usm, soft_purge, soft_purge, []}, {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {load_module, snmpa_net_if, soft_purge, soft_purge, []}, {load_module, snmpm_mpd, soft_purge, soft_purge, []} ] @@ -44,6 +50,7 @@ {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, {update, snmpa_mib, soft, soft_purge, soft_purge, []}, {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mib]}, + {load_module, snmpa_net_if, soft_purge, soft_purge, []}, {load_module, snmpm_mpd, soft_purge, soft_purge, []}, {update, snmpm_server, soft, soft_purge, soft_purge, []} @@ -61,6 +68,7 @@ {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, {update, snmpa_mib, soft, soft_purge, soft_purge, []}, {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mib]}, + {load_module, snmpa_net_if, soft_purge, soft_purge, []}, {load_module, snmpm_mpd, soft_purge, soft_purge, []}, {update, snmpm_net_if, soft, soft_purge, soft_purge, []}, @@ -149,6 +157,11 @@ %% ------D o w n g r a d e --------------------------------------------------- [ + {"4.17", + [ + {load_module, snmpa_net_if, soft_purge, soft_purge, []} + ] + }, {"4.16.2", [ {load_module, snmp_log, soft_purge, soft_purge, []}, @@ -157,6 +170,7 @@ {load_module, snmpa_mpd, soft_purge, soft_purge, [snmpa_usm]}, {load_module, snmpa_usm, soft_purge, soft_purge, []}, {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {load_module, snmpa_net_if, soft_purge, soft_purge, []}, {load_module, snmpm_mpd, soft_purge, soft_purge, []} ] @@ -172,6 +186,7 @@ {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, {update, snmpa_mib, soft, soft_purge, soft_purge, []}, {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mib]}, + {load_module, snmpa_net_if, soft_purge, soft_purge, []}, {load_module, snmpm_mpd, soft_purge, soft_purge, []}, {update, snmpm_server, soft, soft_purge, soft_purge, []} @@ -189,6 +204,7 @@ {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, {update, snmpa_mib, soft, soft_purge, soft_purge, []}, {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mib]}, + {load_module, snmpa_net_if, soft_purge, soft_purge, []}, {load_module, snmpm_mpd, soft_purge, soft_purge, []}, {update, snmpm_net_if, soft, soft_purge, soft_purge, []}, diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk index 4ca1fb7901..21b84f0dc6 100644 --- a/lib/snmp/vsn.mk +++ b/lib/snmp/vsn.mk @@ -1,57 +1,22 @@ #-*-makefile-*- ; force emacs to enter makefile-mode # %CopyrightBegin% -# +# # Copyright Ericsson AB 1997-2010. 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% -SNMP_VSN = 4.17 +SNMP_VSN = 4.17.1 PRE_VSN = APP_VSN = "snmp-$(SNMP_VSN)$(PRE_VSN)" - -TICKETS = OTP-8478 - -TICKETS_4_16_2 = \ - OTP-8563 \ - OTP-8574 \ - OTP-8594 \ - OTP-8595 \ - OTP-8646 \ - OTP-8648 - -TICKETS_4_16_1 = \ - OTP-8480 \ - OTP-8481 - -TICKETS_4_16 = \ - OTP-8395 \ - OTP-8433 \ - OTP-8442 - -TICKETS_4_15 = \ - OTP-8229 \ - OTP-8249 - -TICKETS_4_14 = \ - OTP-8223 \ - OTP-8228 \ - OTP-8237 - -TICKETS_4_13_5 = \ - OTP-8116 \ - OTP-8120 \ - OTP-8181 \ - OTP-8182 - diff --git a/lib/ssh/src/ssh_channel.erl b/lib/ssh/src/ssh_channel.erl index 8a49a44a6c..dcb2d69290 100644 --- a/lib/ssh/src/ssh_channel.erl +++ b/lib/ssh/src/ssh_channel.erl @@ -238,9 +238,19 @@ handle_info(Msg, #state{cm = ConnectionManager, channel_cb = Module, {noreply, State#state{channel_state = ChannelState}}; {ok, ChannelState, Timeout} -> {noreply, State#state{channel_state = ChannelState}, Timeout}; + {stop, Reason, ChannelState} when is_atom(Reason)-> + {stop, Reason, State#state{close_sent = true, + channel_state = ChannelState}}; {stop, ChannelId, ChannelState} -> - ssh_connection:close(ConnectionManager, ChannelId), - {stop, normal, State#state{close_sent = true, + Reason = + case Msg of + {'EXIT', _Pid, shutdown} -> + shutdown; + _ -> + normal + end, + (catch ssh_connection:close(ConnectionManager, ChannelId)), + {stop, Reason, State#state{close_sent = true, channel_state = ChannelState}} end. diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl index cffeade485..9e55312e5f 100644 --- a/lib/ssh/src/ssh_connection_manager.erl +++ b/lib/ssh/src/ssh_connection_manager.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 2008-2010. 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% %% %% @@ -146,6 +146,8 @@ adjust_window(ConnectionManager, Channel, Bytes) -> close(ConnectionManager, ChannelId) -> try call(ConnectionManager, {close, ChannelId}) of ok -> + ok; + {error,normal} -> ok catch exit:{noproc, _} -> @@ -155,6 +157,8 @@ close(ConnectionManager, ChannelId) -> stop(ConnectionManager) -> try call(ConnectionManager, stop) of ok -> + ok; + {error,normal} -> ok catch exit:{noproc, _} -> @@ -593,7 +597,9 @@ call(Pid, Msg, Timeout) -> Result catch exit:{timeout, _} -> - {error, timeout} + {error, timeout}; + exit:{normal, _} -> + {error, normal} end. cast(Pid, Msg) -> diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index ccdbfe4f9a..a8821625a2 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -2,83 +2,3 @@ SSH_VSN = 2.0 APP_VSN = "ssh-$(SSH_VSN)" - -TICKETS = OTP-8524 \ - OTP-8534 \ - OTP-8535 \ - OTP-8550 \ - OTP-8596 \ - OTP-8644 \ - OTP-8645 - -TICKETS_1.1.8 = OTP-8356 \ - OTP-8401 - -TICKETS_1.1.7 = OTP-8121 \ - OTP-8277 \ - OTP-8278 \ - OTP-8201 - -TICKETS_1.1.6 = OTP-8110 \ - OTP-8162 \ - OTP-8173 \ - OTP-8174 \ - OTP-8175 \ - OTP-8176 - -TICKETS_1.1.5 = OTP-8159 \ - OTP-8160 \ - OTP-8161 - -TICKETS_1.1.4 = OTP-8071 - -TICKETS_1.1.3 = OTP-7996 \ - OTP-8034 \ - OTP-8035 - -TICKETS_1.1.2 = OTP-7914 \ - OTP-7917 \ - OTP-7918 \ - OTP-7921 \ - OTP-7919 \ - OTP-7930 \ - OTP-7957 - -TICKETS_1.1.1 = OTP-7828 \ - OTP-7795 \ - OTP-7807 \ - OTP-7808 \ - OTP-7809 - -TICKETS_1.1 = OTP-7676 \ - OTP-7683 \ - OTP-7685 \ - OTP-7766 \ - OTP-7767 \ - OTP-7768 \ - OTP-7770 \ - OTP-7456 \ - OTP-7769 \ - OTP-7516 \ - OTP-7645 \ - -TICKETS_1.0.2 = \ - OTP-7141\ - -TICKETS_1.0.1 = \ - OTP-7318 \ - OTP-7305 \ - OTP-7564 \ - OTP-7565 \ - OTP-7566 \ - -TICKETS_1.0 = \ - OTP-7485 \ - OTP-7504 \ - OTP-7356 \ - OTP-7502 \ - OTP-7503 - -TICKETS_0.9.9.6 = \ - OTP-7246 \ - OTP-7247 \
\ No newline at end of file diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src index 65f23e2f74..88cd73be74 100644 --- a/lib/ssl/src/ssl.appup.src +++ b/lib/ssl/src/ssl.appup.src @@ -1,6 +1,7 @@ %% -*- erlang -*- {"%VSN%", [ + {"4.0", [{restart_application, ssl}]}, {"3.11.1", [{restart_application, ssl}]}, {"3.11", [{restart_application, ssl}]}, {"3.10", [{restart_application, ssl}]}, @@ -15,6 +16,7 @@ {"3.10.9", [{restart_application, ssl}]} ], [ + {"4.0", [{restart_application, ssl}]}, {"3.11.1", [{restart_application, ssl}]}, {"3.11", [{restart_application, ssl}]}, {"3.10", [{restart_application, ssl}]}, diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index df4cd7c84d..6e26f05c3d 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -77,8 +77,9 @@ stop() -> application:stop(ssl). %%-------------------------------------------------------------------- --spec connect(host() | port(), port_num(), list()) -> {ok, #sslsocket{}}. --spec connect(host() | port(), port_num(), list(), timeout()) -> {ok, #sslsocket{}}. +-spec connect(host() | port(), list()) -> {ok, #sslsocket{}}. +-spec connect(host() | port(), list() | port_num(), timeout() | list()) -> {ok, #sslsocket{}}. +-spec connect(host() | port(), port_num(), list(), timeout()) -> {ok, #sslsocket{}}. %% %% Description: Connect to a ssl server. %%-------------------------------------------------------------------- @@ -215,8 +216,8 @@ ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) -> {ok, #config{cb=CbInfo,ssl=SslOpts, emulated=EmOpts}} -> {ok, Port} = inet:port(Socket), ssl_connection:ssl_accept(Port, Socket, - {SslOpts, EmOpts}, - self(), CbInfo, Timeout) + {SslOpts, EmOpts}, + self(), CbInfo, Timeout) catch Error = {error, _Reason} -> Error end. @@ -326,7 +327,7 @@ decode_peercert(BinCert, Opts) -> {ok, BinCert} end. -select_part(otp, {ok, Cert}, Opts) -> +select_part(otp, Cert, Opts) -> case lists:member(subject, Opts) of true -> TBS = Cert#'OTPCertificate'.tbsCertificate, @@ -335,7 +336,7 @@ select_part(otp, {ok, Cert}, Opts) -> {ok, Cert} end; -select_part(plain, {ok, Cert}, Opts) -> +select_part(plain, Cert, Opts) -> case lists:member(subject, Opts) of true -> TBS = Cert#'Certificate'.tbsCertificate, @@ -446,8 +447,8 @@ session_info(#sslsocket{pid = Pid, fd = new_ssl}) -> ssl_connection:session_info(Pid). %%--------------------------------------------------------------- --spec versions() -> [{{ssl_app, string()}, {supported, [tls_version()]}, - {available, [tls_version()]}}]. +-spec versions() -> [{ssl_app, string()} | {supported, [tls_atom_version()]} | + {available, [tls_atom_version()]}]. %% %% Description: Returns a list of relevant versions. %%-------------------------------------------------------------------- @@ -457,6 +458,7 @@ versions() -> AvailableVsns = ?DEFAULT_SUPPORTED_VERSIONS, [{ssl_app, ?VSN}, {supported, SupportedVsns}, {available, AvailableVsns}]. + %%--------------------------------------------------------------- -spec renegotiate(#sslsocket{}) -> ok | {error, reason()}. %% diff --git a/lib/ssl/src/ssl_app.erl b/lib/ssl/src/ssl_app.erl index d9a354086d..8d50fd7bdb 100644 --- a/lib/ssl/src/ssl_app.erl +++ b/lib/ssl/src/ssl_app.erl @@ -29,14 +29,14 @@ %%-------------------------------------------------------------------- -spec start(normal | {takeover, node()} | {failover, node()}, list()) -> - {ok, pid()} | {ok, pid(), term()} | {error, term()}. + ignore | {ok, pid()} | {error, term()}. %%-------------------------------------------------------------------- start(_Type, _StartArgs) -> ssl_sup:start_link(). %-------------------------------------------------------------------- -spec stop(term())-> ok. -%%-------------------------------------------------------------------- +%%-------------------------------------------------------------------- stop(_State) -> ok. diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index 8a79f75725..917e75157b 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -56,7 +56,7 @@ %%-------------------------------------------------------------------- trusted_cert_and_path(CertChain, CertDbRef, Verify) -> [Cert | RestPath] = lists:reverse(CertChain), - {ok, OtpCert} = public_key:pkix_decode_cert(Cert, otp), + OtpCert = public_key:pkix_decode_cert(Cert, otp), IssuerAnPath = case public_key:pkix_is_self_signed(OtpCert) of true -> @@ -94,14 +94,14 @@ trusted_cert_and_path(CertChain, CertDbRef, Verify) -> %%-------------------------------------------------------------------- -spec certificate_chain(undefined | binary(), certdb_ref()) -> - {error, no_cert} | [der_cert()]. + {error, no_cert} | {ok, [der_cert()]}. %% %% Description: Return the certificate chain to send to peer. %%-------------------------------------------------------------------- certificate_chain(undefined, _CertsDbRef) -> {error, no_cert}; certificate_chain(OwnCert, CertsDbRef) -> - {ok, ErlCert} = public_key:pkix_decode_cert(OwnCert, otp), + ErlCert = public_key:pkix_decode_cert(OwnCert, otp), certificate_chain(ErlCert, OwnCert, CertsDbRef, [OwnCert]). %%-------------------------------------------------------------------- -spec file_to_certificats(string()) -> [der_cert()]. @@ -110,7 +110,7 @@ certificate_chain(OwnCert, CertsDbRef) -> %%-------------------------------------------------------------------- file_to_certificats(File) -> {ok, List} = ssl_manager:cache_pem_file(File), - [Bin || {cert, Bin, not_encrypted} <- List]. + [Bin || {'Certificate', Bin, not_encrypted} <- List]. %%-------------------------------------------------------------------- -spec validate_extensions([#'Extension'{}], term(), [#'Extension'{}], boolean(), list(), client | server) -> {[#'Extension'{}], term(), list()}. @@ -219,7 +219,7 @@ certificate_chain(CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned) -> case ssl_manager:lookup_trusted_cert(CertsDbRef, SerialNr, Issuer) of {ok, {IssuerCert, ErlCert}} -> - {ok, ErlCert} = public_key:pkix_decode_cert(IssuerCert, otp), + ErlCert = public_key:pkix_decode_cert(IssuerCert, otp), certificate_chain(ErlCert, IssuerCert, CertsDbRef, [IssuerCert | Chain]); _ -> diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl index e953821057..00d3079cb3 100644 --- a/lib/ssl/src/ssl_certificate_db.erl +++ b/lib/ssl/src/ssl_certificate_db.erl @@ -54,10 +54,9 @@ remove(Dbs) -> lists:foreach(fun(Db) -> true = ets:delete(Db) end, Dbs). %%-------------------------------------------------------------------- --spec lookup_trusted_cert(reference(), serialnumber(), issuer()) -> {der_cert(), #'OTPCertificate'{}}. +-spec lookup_trusted_cert(reference(), serialnumber(), issuer()) -> + undefined | {ok, {der_cert(), #'OTPCertificate'{}}}. -%% SerialNumber = integer() -%% Issuer = {rdnSequence, IssuerAttrs} %% %% Description: Retrives the trusted certificate identified by %% <SerialNumber, Issuer>. Ref is used as it is specified @@ -101,10 +100,11 @@ add_trusted_certs(Pid, File, [CertsDb, FileToRefDb, PidToFileDb]) -> %% Description: Cache file as binary in DB %%-------------------------------------------------------------------- cache_pem_file(Pid, File, [CertsDb, _FileToRefDb, PidToFileDb]) -> - Res = {ok, Content} = public_key:pem_to_der(File), + {ok, PemBin} = file:read_file(File), + Content = public_key:pem_decode(PemBin), insert({file, File}, Content, CertsDb), insert(Pid, File, PidToFileDb), - Res. + {ok, Content}. %%-------------------------------------------------------------------- -spec remove_trusted_certs(pid(), certdb_ref()) -> term(). @@ -138,13 +138,13 @@ remove_trusted_certs(Pid, [CertsDb, FileToRefDb, PidToFileDb]) -> end. %%-------------------------------------------------------------------- --spec issuer_candidate(no_candidate | cert_key()) -> - {cert_key(), der_cert()} | no_more_candidates. +-spec issuer_candidate(no_candidate | cert_key() | {file, term()}) -> + {cert_key(),{der_cert(), #'OTPCertificate'{}}} | no_more_candidates. %% %% Description: If a certificat does not define its issuer through %% the extension 'ce-authorityKeyIdentifier' we can %% try to find the issuer in the database over known -%% certificates. +%% certificates. %%-------------------------------------------------------------------- issuer_candidate(no_candidate) -> Db = certificate_db_name(), @@ -203,14 +203,15 @@ remove_certs(Ref, CertsDb) -> ets:match_delete(CertsDb, {{Ref, '_', '_'}, '_'}). add_certs_from_file(File, Ref, CertsDb) -> - Decode = fun(Cert) -> - {ok, ErlCert} = public_key:pkix_decode_cert(Cert, otp), + Add = fun(Cert) -> + ErlCert = public_key:pkix_decode_cert(Cert, otp), TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate, SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber, - Issuer = public_key:pkix_normalize_general_name( + Issuer = public_key:pkix_normalize_name( TBSCertificate#'OTPTBSCertificate'.issuer), insert({Ref, SerialNumber, Issuer}, {Cert,ErlCert}, CertsDb) end, - {ok,Der} = public_key:pem_to_der(File), - [Decode(Cert) || {cert, Cert, not_encrypted} <- Der]. + {ok, PemBin} = file:read_file(File), + PemEntries = public_key:pem_decode(PemBin), + [Add(Cert) || {'Certificate', Cert, not_encrypted} <- PemEntries]. diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index a6e80047c2..8230149304 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -40,7 +40,7 @@ -compile(inline). %%-------------------------------------------------------------------- --spec security_parameters(erl_cipher_suite(), #security_parameters{}) -> +-spec security_parameters(cipher_suite(), #security_parameters{}) -> #security_parameters{}. %% %% Description: Returns a security parameters record where the @@ -119,7 +119,7 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, %%-------------------------------------------------------------------- -spec decipher(cipher_enum(), integer(), #cipher_state{}, binary(), tls_version()) -> - {binary(), #cipher_state{}}. + {binary(), binary(), #cipher_state{}} | #alert{}. %% %% Description: Decrypts the data and the MAC using cipher described %% by cipher_enum() and updating the cipher state. @@ -370,7 +370,7 @@ openssl_suite_name(Cipher) -> filter(undefined, Ciphers) -> Ciphers; filter(DerCert, Ciphers) -> - {ok, OtpCert} = public_key:pkix_decode_cert(DerCert, otp), + OtpCert = public_key:pkix_decode_cert(DerCert, otp), SigAlg = OtpCert#'OTPCertificate'.signatureAlgorithm, case ssl_certificate:signature_type(SigAlg#'SignatureAlgorithm'.algorithm) of rsa -> @@ -506,6 +506,12 @@ generic_stream_cipher_from_bin(T, HashSz) -> is_correct_padding(_, {3, 0}) -> true; +%% For interoperability reasons we do not check the padding in TLS 1.0 as it +%% is not strictly required and breaks interopability with for instance +%% Google. +is_correct_padding(_, {3, 1}) -> + true; +%% Padding must be check in TLS 1.1 and after is_correct_padding(#generic_block_cipher{padding_length = Len, padding = Padding}, _) -> list_to_binary(lists:duplicate(Len, Len)) == Padding. diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl index 19de709d9c..8bd68cc190 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -28,7 +28,7 @@ -type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc' | aes_128_cbc | aes_256_cbc. --type hash() :: sha | md5. +-type hash() :: null | sha | md5. -type erl_cipher_suite() :: {key_algo(), cipher(), hash()}. -type cipher_suite() :: binary(). -type cipher_enum() :: integer(). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 5b4b129e30..76422155a5 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -125,8 +125,9 @@ send(Pid, Data) -> recv(Pid, Length, Timeout) -> sync_send_all_state_event(Pid, {recv, Length}, Timeout). %%-------------------------------------------------------------------- --spec connect(host(), port_num(), port(), list(), pid(), tuple(), timeout()) -> - {ok, #sslsocket{}} | {error, reason()}. +-spec connect(host(), port_num(), port(), {#ssl_options{}, #socket_options{}}, + pid(), tuple(), timeout()) -> + {ok, #sslsocket{}} | {error, reason()}. %% %% Description: Connect to a ssl server. %%-------------------------------------------------------------------- @@ -138,7 +139,8 @@ connect(Host, Port, Socket, Options, User, CbInfo, Timeout) -> {error, ssl_not_started} end. %%-------------------------------------------------------------------- --spec ssl_accept(port_num(), port(), list(), pid(), tuple(), timeout()) -> +-spec ssl_accept(port_num(), port(), {#ssl_options{}, #socket_options{}}, + pid(), tuple(), timeout()) -> {ok, #sslsocket{}} | {error, reason()}. %% %% Description: Performs accept on a ssl listen socket. e.i. performs @@ -253,7 +255,7 @@ session_info(ConnectionPid) -> sync_send_all_state_event(ConnectionPid, session_info). %%-------------------------------------------------------------------- --spec peer_certificate(pid()) -> {ok, binary()} | {error, reason()}. +-spec peer_certificate(pid()) -> {ok, binary()| undefined} | {error, reason()}. %% %% Description: Returns the peer cert %%-------------------------------------------------------------------- @@ -288,9 +290,10 @@ start_link(Role, Host, Port, Socket, Options, User, CbInfo) -> %% gen_fsm callbacks %%==================================================================== %%-------------------------------------------------------------------- --spec init(list()) -> {ok, state_name(), #state{}} - | {ok, state_name(), #state{}, timeout()} | - ignore | {stop, term()}. +-spec init(list()) -> {ok, state_name(), #state{}} | {stop, term()}. +%% Possible return values not used now. +%% | {ok, state_name(), #state{}, timeout()} | +%% ignore %% Description:Whenever a gen_fsm is started using gen_fsm:start/[3,4] or %% gen_fsm:start_link/3,4, this function is called by the new process to %% initialize. @@ -720,7 +723,9 @@ connection(#client_hello{} = Hello, #state{role = server} = State) -> connection(Msg, State) -> handle_unexpected_message(Msg, connection, State). %%-------------------------------------------------------------------- --spec handle_event(term(), state_name(), #state{}) -> gen_fsm_state_return(). +-spec handle_event(term(), state_name(), #state{}) -> term(). +%% As it is not currently used gen_fsm_state_return() makes +%% dialyzer unhappy! %% %% Description: Whenever a gen_fsm receives an event sent using %% gen_fsm:send_all_state_event/2, this function is called to handle @@ -1038,20 +1043,22 @@ ssl_init(SslOpts, Role) -> init_certificates(#ssl_options{cacertfile = CACertFile, certfile = CertFile}, Role) -> + {ok, CertDbRef, CacheRef} = + try + {ok, _, _} = ssl_manager:connection_init(CACertFile, Role) + catch + Error:Reason -> + handle_file_error(?LINE, Error, Reason, CACertFile, ecacertfile, + erlang:get_stacktrace()) + end, + init_certificates(CertDbRef, CacheRef, CertFile, Role). - case ssl_manager:connection_init(CACertFile, Role) of - {ok, CertDbRef, CacheRef} -> - init_certificates(CertDbRef, CacheRef, CertFile, Role); - {error, Reason} -> - handle_file_error(?LINE, error, Reason, CACertFile, ecacertfile, - erlang:get_stacktrace()) - end. init_certificates(CertDbRef, CacheRef, CertFile, client) -> try [OwnCert] = ssl_certificate:file_to_certificats(CertFile), {ok, CertDbRef, CacheRef, OwnCert} - catch _E:_R -> + catch _Error:_Reason -> {ok, CertDbRef, CacheRef, undefined} end; @@ -1068,15 +1075,15 @@ init_certificates(CertDbRef, CacheRef, CertFile, server) -> init_private_key(undefined, "", _Password, client) -> undefined; init_private_key(undefined, KeyFile, Password, _) -> - case ssl_manager:cache_pem_file(KeyFile) of - {ok, List} -> - [Der] = [Der || Der = {PKey, _ , _} <- List, - PKey =:= rsa_private_key orelse - PKey =:= dsa_private_key], - {ok, Decoded} = public_key:decode_private_key(Der,Password), - Decoded; - {error, Reason} -> - handle_file_error(?LINE, error, Reason, KeyFile, ekeyfile, + try + {ok, List} = ssl_manager:cache_pem_file(KeyFile), + [PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List, + PKey =:= 'RSAPrivateKey' orelse + PKey =:= 'DSAPrivateKey'], + public_key:pem_entry_decode(PemEntry, Password) + catch + Error:Reason -> + handle_file_error(?LINE, Error, Reason, KeyFile, ekeyfile, erlang:get_stacktrace()) end; @@ -1088,6 +1095,7 @@ handle_file_error(Line, Error, {badmatch, Reason}, File, Throw, Stack) -> handle_file_error(Line, Error, Reason, File, Throw, Stack) -> file_error(Line, Error, Reason, File, Throw, Stack). +-spec(file_error/6 :: (_,_,_,_,_,_) -> no_return()). file_error(Line, Error, Reason, File, Throw, Stack) -> Report = io_lib:format("SSL: ~p: ~p:~p ~s~n ~p~n", [Line, Error, Reason, File, Stack]), @@ -1099,17 +1107,18 @@ init_diffie_hellman(_, client) -> init_diffie_hellman(undefined, _) -> ?DEFAULT_DIFFIE_HELLMAN_PARAMS; init_diffie_hellman(DHParamFile, server) -> - case ssl_manager:cache_pem_file(DHParamFile) of - {ok, List} -> - case [Der || Der = {dh_params, _ , _} <- List] of - [Der] -> - {ok, Decoded} = public_key:decode_dhparams(Der), - Decoded; - [] -> - ?DEFAULT_DIFFIE_HELLMAN_PARAMS - end; - {error, Reason} -> - handle_file_error(?LINE, error, Reason, DHParamFile, edhfile, erlang:get_stacktrace()) + try + {ok, List} = ssl_manager:cache_pem_file(DHParamFile), + case [Entry || Entry = {'DHParameter', _ , _} <- List] of + [Entry] -> + public_key:pem_entry_decode(Entry); + [] -> + ?DEFAULT_DIFFIE_HELLMAN_PARAMS + end + catch + Error:Reason -> + handle_file_error(?LINE, Error, Reason, + DHParamFile, edhfile, erlang:get_stacktrace()) end. sync_send_all_state_event(FsmPid, Event) -> @@ -1178,7 +1187,7 @@ verify_client_cert(#state{client_certificate_requested = true, role = client, tls_handshake_hashes = Hashes1}; ignore -> State; - #alert{} = Alert -> + #alert{} = Alert -> handle_own_alert(Alert, Version, certify, State) end; @@ -1186,18 +1195,19 @@ verify_client_cert(#state{client_certificate_requested = false} = State) -> State. do_server_hello(Type, #state{negotiated_version = Version, - session = Session, + session = #session{session_id = SessId} = Session, connection_states = ConnectionStates0, renegotiation = {Renegotiation, _}} = State0) when is_atom(Type) -> + ServerHello = - ssl_handshake:server_hello(Session#session.session_id, Version, + ssl_handshake:server_hello(SessId, Version, ConnectionStates0, Renegotiation), State1 = server_hello(ServerHello, State0), case Type of new -> - do_server_hello(ServerHello, State1); + new_server_hello(ServerHello, State1); resumed -> ConnectionStates1 = State1#state.connection_states, case ssl_handshake:master_secret(Version, Session, @@ -1216,9 +1226,9 @@ do_server_hello(Type, #state{negotiated_version = Version, handle_own_alert(Alert, Version, hello, State1), {stop, normal, State1} end - end; + end. -do_server_hello(#server_hello{cipher_suite = CipherSuite, +new_server_hello(#server_hello{cipher_suite = CipherSuite, compression_method = Compression, session_id = SessionId}, #state{session = Session0, @@ -1343,7 +1353,7 @@ certify_server(#state{transport_cb = Transport, key_exchange(#state{role = server, key_algorithm = rsa} = State) -> State; key_exchange(#state{role = server, key_algorithm = Algo, - diffie_hellman_params = Params, + diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params, private_key = PrivateKey, connection_states = ConnectionStates0, negotiated_version = Version, @@ -1354,7 +1364,7 @@ key_exchange(#state{role = server, key_algorithm = Algo, when Algo == dhe_dss; Algo == dhe_rsa -> - Keys = public_key:gen_key(Params), + Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]), ConnectionState = ssl_record:pending_connection_state(ConnectionStates0, read), SecParams = ConnectionState#connection_state.security_parameters, @@ -1406,6 +1416,8 @@ key_exchange(#state{role = client, State#state{connection_states = ConnectionStates1, tls_handshake_hashes = Hashes1}. +-spec(rsa_key_exchange/2 :: (_,_) -> no_return()). + rsa_key_exchange(PremasterSecret, PublicKeyInfo = {Algorithm, _, _}) when Algorithm == ?rsaEncryption; Algorithm == ?md2WithRSAEncryption; @@ -1536,7 +1548,7 @@ verify_dh_params(Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) -> false end; verify_dh_params(Signed, Hash, {?'id-dsa', PublicKey, PublicKeyParams}) -> - public_key:verify_signature(Hash, none, Signed, PublicKey, PublicKeyParams). + public_key:verify(Hash, none, Signed, {PublicKey, PublicKeyParams}). cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) -> @@ -1563,7 +1575,7 @@ encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) -> ssl_record:encode_change_cipher_spec(Version, ConnectionStates). encode_handshake(HandshakeRec, Version, ConnectionStates, Hashes) -> - encode_handshake(HandshakeRec, undefined, Version, + encode_handshake(HandshakeRec, null, Version, ConnectionStates, Hashes). encode_handshake(HandshakeRec, SigAlg, Version, ConnectionStates0, Hashes0) -> @@ -1726,11 +1738,13 @@ format_packet_error(#socket_options{active = _, mode = Mode}, Data) -> format_reply(binary, _, N, Data) when N > 0 -> % Header mode header(N, Data); -format_reply(binary, _, _, Data) -> Data; -format_reply(list, Packet, _, Data) when is_integer(Packet); Packet == raw -> - binary_to_list(Data); +format_reply(binary, _, _, Data) -> + Data; +format_reply(list, Packet, _, Data) + when Packet == http; Packet == {http, headers}; Packet == http_bin; Packet == {http_bin, headers} -> + Data; format_reply(list, _,_, Data) -> - Data. + binary_to_list(Data). header(0, <<>>) -> <<>>; @@ -2154,7 +2168,7 @@ renegotiate(#state{role = server, negotiated_version = Version, connection_states = ConnectionStates0} = State0) -> HelloRequest = ssl_handshake:hello_request(), - Frag = ssl_handshake:encode_handshake(HelloRequest, Version, undefined), + Frag = ssl_handshake:encode_handshake(HelloRequest, Version, null), Hs0 = ssl_handshake:init_hashes(), {BinMsg, ConnectionStates} = ssl_record:encode_handshake(Frag, Version, ConnectionStates0), diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index fcc30f6137..3d831eae02 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -42,8 +42,10 @@ encode_handshake/3, init_hashes/0, update_hashes/2, decrypt_premaster_secret/2]). --type tls_handshake() :: #client_hello{} | #server_hello{} | #server_hello_done{} | -#certificate{} | #client_key_exchange{} | #finished{} | #certificate_verify{}. +-type tls_handshake() :: #client_hello{} | #server_hello{} | + #server_hello_done{} | #certificate{} | #certificate_request{} | + #client_key_exchange{} | #finished{} | #certificate_verify{} | + #hello_request{}. %%==================================================================== %% Internal application API @@ -64,7 +66,7 @@ client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions, Version = ssl_record:highest_protocol_version(lists:map(Fun, Versions)), Pending = ssl_record:pending_connection_state(ConnectionStates, read), SecParams = Pending#connection_state.security_parameters, - Ciphers = available_suites(Cert, UserSuites, Version), + Ciphers = available_suites(UserSuites, Version), Id = ssl_manager:client_session_id(Host, Port, SslOpts), @@ -110,7 +112,7 @@ hello_request() -> #connection_states{} | {port_num(), #session{}, cache_ref(), atom(), #connection_states{}, binary()}, boolean()) -> {tls_version(), session_id(), #connection_states{}}| - {tls_version(), {resumed | new, session_id()}, + {tls_version(), {resumed | new, #session{}}, #connection_states{}} | #alert{}. %% %% Description: Handles a recieved hello message @@ -232,7 +234,7 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbRef, end. %%-------------------------------------------------------------------- --spec certificate(der_cert(), term(), client | server) -> #certificate{}. +-spec certificate(der_cert(), term(), client | server) -> #certificate{} | #alert{}. %% %% Description: Creates a certificate message. %%-------------------------------------------------------------------- @@ -260,8 +262,8 @@ certificate(OwnCert, CertDbRef, server) -> %%-------------------------------------------------------------------- -spec client_certificate_verify(undefined | der_cert(), binary(), tls_version(), key_algo(), private_key(), - {binary(), binary()}) -> - #certificate_verify{} | ignore. + {{binary(), binary()},{binary(), binary()}}) -> + #certificate_verify{} | ignore | #alert{}. %% %% Description: Creates a certificate_verify message, called by the client. %%-------------------------------------------------------------------- @@ -283,9 +285,9 @@ client_certificate_verify(OwnCert, MasterSecret, Version, Algorithm, end. %%-------------------------------------------------------------------- --spec certificate_verify(binary(), public_key_info(), tls_version(), - binary(), key_algo(), - {binary(), binary()}) -> valid | #alert{}. +%% -spec certificate_verify(binary(), public_key_info(), tls_version(), +%% binary(), key_algo(), +%% {_, {binary(), binary()}}) -> valid | #alert{}. %% %% Description: Checks that the certificate_verify message is valid. %%-------------------------------------------------------------------- @@ -306,7 +308,7 @@ certificate_verify(Signature, {_, PublicKey, PublicKeyParams}, Version, MasterSecret, dhe_dss = Algorithm, {_, Hashes0}) -> Hashes = calc_certificate_verify(Version, MasterSecret, Algorithm, Hashes0), - case public_key:verify_signature(Hashes, none, Signature, PublicKey, PublicKeyParams) of + case public_key:verify(Hashes, none, Signature, {PublicKey, PublicKeyParams}) of true -> valid; false -> @@ -335,7 +337,7 @@ certificate_request(ConnectionStates, CertDbRef) -> -spec key_exchange(client | server, {premaster_secret, binary(), public_key_info()} | {dh, binary()} | - {dh, binary(), #'DHParameter'{}, key_algo(), + {dh, {binary(), binary()}, #'DHParameter'{}, key_algo(), binary(), binary(), private_key()}) -> #client_key_exchange{} | #server_key_exchange{}. %% @@ -412,7 +414,7 @@ master_secret(Version, PremasterSecret, ConnectionStates, Role) -> end. %%-------------------------------------------------------------------- --spec finished(tls_version(), client | server, binary(), {binary(), binary()}) -> +-spec finished(tls_version(), client | server, binary(), {{binary(), binary()},_}) -> #finished{}. %% %% Description: Creates a handshake finished message @@ -423,7 +425,7 @@ finished(Version, Role, MasterSecret, {Hashes, _}) -> % use the current hashes %%-------------------------------------------------------------------- -spec verify_connection(tls_version(), #finished{}, client | server, binary(), - {binary(), binary()}) -> verified | #alert{}. + {_, {binary(), binary()}}) -> verified | #alert{}. %% %% Description: Checks the ssl handshake finished message to verify %% the connection. @@ -448,7 +450,7 @@ server_hello_done() -> #server_hello_done{}. %%-------------------------------------------------------------------- --spec encode_handshake(tls_handshake(), tls_version(), key_algo()) -> binary(). +-spec encode_handshake(tls_handshake(), tls_version(), key_algo()) -> iolist(). %% %% Description: Encode a handshake packet to binary %%-------------------------------------------------------------------- @@ -459,8 +461,8 @@ encode_handshake(Package, Version, KeyAlg) -> [MsgType, ?uint24(Len), Bin]. %%-------------------------------------------------------------------- --spec get_tls_handshake(binary(), binary(), key_algo(), tls_version()) -> - {[tls_handshake()], [binary()], binary()}. +-spec get_tls_handshake(binary(), binary() | iolist(), key_algo(), tls_version()) -> + {[tls_handshake()], binary()}. %% %% Description: Given buffered and new data from ssl_record, collects %% and returns it as a list of handshake messages, also returns leftover @@ -524,13 +526,16 @@ select_session(Hello, Port, Session, Version, {resumed, CacheCb:lookup(Cache, {Port, SessionId})} end. -available_suites(Cert, UserSuites, Version) -> +available_suites(UserSuites, Version) -> case UserSuites of [] -> - ssl_cipher:filter(Cert, ssl_cipher:suites(Version)); + ssl_cipher:suites(Version); _ -> - ssl_cipher:filter(Cert, UserSuites) + UserSuites end. + +available_suites(ServerCert, UserSuites, Version) -> + ssl_cipher:filter(ServerCert, available_suites(UserSuites, Version)). cipher_suites(Suites, false) -> [?TLS_EMPTY_RENEGOTIATION_INFO_SCSV | Suites]; @@ -1042,9 +1047,10 @@ certificate_authorities(CertDbRef) -> Authorities = certificate_authorities_from_db(CertDbRef), Enc = fun(#'OTPCertificate'{tbsCertificate=TBSCert}) -> OTPSubj = TBSCert#'OTPTBSCertificate'.subject, - Subj = public_key:pkix_transform(OTPSubj, encode), - {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj), - DNEncodedBin = iolist_to_binary(DNEncoded), + DNEncodedBin = public_key:pkix_encode('Name', OTPSubj, otp), + %%Subj = public_key:pkix_transform(OTPSubj, encode), + %% {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj), + %% DNEncodedBin = iolist_to_binary(DNEncoded), DNEncodedLen = byte_size(DNEncodedBin), <<?UINT16(DNEncodedLen), DNEncodedBin/binary>> end, @@ -1068,7 +1074,7 @@ digitally_signed(Hash, #'RSAPrivateKey'{} = Key) -> public_key:encrypt_private(Hash, Key, [{rsa_pad, rsa_pkcs1_padding}]); digitally_signed(Hash, #'DSAPrivateKey'{} = Key) -> - public_key:sign(none, Hash, Key). + public_key:sign(Hash, none, Key). calc_master_secret({3,0}, PremasterSecret, ClientRandom, ServerRandom) -> ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom); diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index ddace02dea..337403531e 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -96,12 +96,12 @@ -type from() :: term(). -type host() :: string() | tuple(). -type port_num() :: integer(). --type session_id() :: binary(). +-type session_id() :: 0 | binary(). -type tls_version() :: {integer(), integer()}. -type tls_atom_version() :: sslv3 | tlsv1. -type cache_ref() :: term(). -type certdb_ref() :: term(). --type key_algo() :: rsa | dhe_rsa | dhe_dss. +-type key_algo() :: null | rsa | dhe_rsa | dhe_dss. -type enum_algo() :: integer(). -type public_key() :: #'RSAPublicKey'{} | integer(). -type public_key_params() :: #'Dss-Parms'{} | term(). diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index af30f78dbf..459dcefb79 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -29,7 +29,8 @@ %% Internal application API -export([start_link/1, connection_init/2, cache_pem_file/1, - lookup_trusted_cert/3, issuer_candidate/1, client_session_id/3, server_session_id/3, + lookup_trusted_cert/3, issuer_candidate/1, client_session_id/3, + server_session_id/3, register_session/2, register_session/3, invalidate_session/2, invalidate_session/3]). @@ -88,14 +89,17 @@ cache_pem_file(File) -> end. %%-------------------------------------------------------------------- -spec lookup_trusted_cert(reference(), serialnumber(), issuer()) -> - {der_cert(), #'OTPCertificate'{}}. + undefined | + {ok, {der_cert(), #'OTPCertificate'{}}}. %% -%% Description: Lookup the trusted cert with Key = {reference(), serialnumber(), issuer()}. -%%-------------------------------------------------------------------- +%% Description: Lookup the trusted cert with Key = {reference(), +%% serialnumber(), issuer()}. +%% -------------------------------------------------------------------- lookup_trusted_cert(Ref, SerialNumber, Issuer) -> ssl_certificate_db:lookup_trusted_cert(Ref, SerialNumber, Issuer). %%-------------------------------------------------------------------- --spec issuer_candidate(cert_key()) -> {cert_key(), der_cert()} | no_more_candidates. +-spec issuer_candidate(cert_key() | no_candidate) -> + {cert_key(), {der_cert(), #'OTPCertificate'{}}} | no_more_candidates. %% %% Description: Return next issuer candidate. %%-------------------------------------------------------------------- @@ -143,8 +147,9 @@ invalidate_session(Port, Session) -> %%==================================================================== %%-------------------------------------------------------------------- --spec init(list()) -> {ok, #state{}} | {ok, #state{}, timeout()} | - ignore | {stop, term()}. +-spec init(list()) -> {ok, #state{}}. +%% Possible return values not used now. +%% | {ok, #state{}, timeout()} | ignore | {stop, term()}. %% %% Description: Initiates the server %%-------------------------------------------------------------------- @@ -164,12 +169,13 @@ init([Opts]) -> session_validation_timer = Timer}}. %%-------------------------------------------------------------------- --spec handle_call(msg(), from(), #state{}) -> {reply, reply(), #state{}} | - {reply, reply(), #state{}, timeout()} | - {noreply, #state{}} | - {noreply, #state{}, timeout()} | - {stop, reason(), reply(), #state{}} | - {stop, reason(), #state{}}. +-spec handle_call(msg(), from(), #state{}) -> {reply, reply(), #state{}}. +%% Possible return values not used now. +%% {reply, reply(), #state{}, timeout()} | +%% {noreply, #state{}} | +%% {noreply, #state{}, timeout()} | +%% {stop, reason(), reply(), #state{}} | +%% {stop, reason(), #state{}}. %% %% Description: Handling call messages %%-------------------------------------------------------------------- @@ -216,9 +222,10 @@ handle_call({{cache_pem, File},Pid}, _, State = #state{certificate_db = Db}) -> {reply, {error, Reason}, State} end. %%-------------------------------------------------------------------- --spec handle_cast(msg(), #state{}) -> {noreply, #state{}} | - {noreply, #state{}, timeout()} | - {stop, reason(), #state{}}. +-spec handle_cast(msg(), #state{}) -> {noreply, #state{}}. +%% Possible return values not used now. +%% | {noreply, #state{}, timeout()} | +%% {stop, reason(), #state{}}. %% %% Description: Handling cast messages %%-------------------------------------------------------------------- @@ -253,9 +260,10 @@ handle_cast({invalidate_session, Port, #session{session_id = ID}}, {noreply, State}. %%-------------------------------------------------------------------- --spec handle_info(msg(), #state{}) -> {noreply, #state{}} | - {noreply, #state{}, timeout()} | - {stop, reason(), #state{}}. +-spec handle_info(msg(), #state{}) -> {noreply, #state{}}. +%% Possible return values not used now. +%% |{noreply, #state{}, timeout()} | +%% {stop, reason(), #state{}}. %% %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index 90615c22a1..acd0d49c19 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -149,7 +149,7 @@ set_mac_secret(ReadMacSecret, WriteMacSecret, %%-------------------------------------------------------------------- --spec set_master_secret(binary(), #connection_state{}) -> #connection_states{}. +-spec set_master_secret(binary(), #connection_states{}) -> #connection_states{}. %% %% Description: Set master_secret in pending connection states %%-------------------------------------------------------------------- @@ -306,7 +306,7 @@ set_pending_cipher_state(#connection_states{pending_read = Read, pending_write = Write#connection_state{cipher_state = ClientState}}. %%-------------------------------------------------------------------- --spec get_tls_records(binary(), binary()) -> {[binary()], binary()}. +-spec get_tls_records(binary(), binary()) -> {[binary()], binary()} | #alert{}. %% %% Description: Given old buffer and new data from TCP, packs up a records %% and returns it as a list of tls_compressed binaries also returns leftover @@ -372,7 +372,8 @@ get_tls_records_aux(Data, Acc) -> {lists:reverse(Acc), Data}. %%-------------------------------------------------------------------- --spec protocol_version(tls_atom_version()) -> tls_version(). +-spec protocol_version(tls_atom_version() | tls_version()) -> + tls_version() | tls_atom_version(). %% %% Description: Creates a protocol version record from a version atom %% or vice versa. @@ -467,7 +468,7 @@ is_acceptable_version(_) -> false. %%-------------------------------------------------------------------- --spec compressions() -> binary(). +-spec compressions() -> [binary()]. %% %% Description: return a list of compressions supported (currently none) %%-------------------------------------------------------------------- @@ -476,7 +477,7 @@ compressions() -> %%-------------------------------------------------------------------- -spec decode_cipher_text(#ssl_tls{}, #connection_states{}) -> - {#ssl_tls{}, #connection_states{}}. + {#ssl_tls{}, #connection_states{}}| #alert{}. %% %% Description: Decode cipher text %%-------------------------------------------------------------------- diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl index e9755cb0e1..6db13e5b7a 100644 --- a/lib/ssl/src/ssl_session.erl +++ b/lib/ssl/src/ssl_session.erl @@ -35,7 +35,7 @@ -type seconds() :: integer(). %%-------------------------------------------------------------------- --spec is_new(binary(), binary()) -> boolean(). +-spec is_new(session_id(), session_id()) -> boolean(). %% %% Description: Checks if the session id decided by the server is a %% new or resumed sesion id. diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl index 375adf263a..1add203fb0 100644 --- a/lib/ssl/src/ssl_ssl3.erl +++ b/lib/ssl/src/ssl_ssl3.erl @@ -121,9 +121,10 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, Length, Fragment) -> ?DBG_HEX(Mac), Mac. --spec setup_keys(binary(), binary(), binary(), binary(), - integer(), integer(), binary()) -> {binary(), binary(), binary(), - binary(), binary(), binary()}. +-spec setup_keys(binary(), binary(), binary(), + integer(), integer(), term(), integer()) -> + {binary(), binary(), binary(), + binary(), binary(), binary()}. setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) -> KeyBlock = generate_keyblock(MasterSecret, ServerRandom, ClientRandom, diff --git a/lib/ssl/src/ssl_sup.erl b/lib/ssl/src/ssl_sup.erl index b7cb5c3ab3..316ed8a4e9 100644 --- a/lib/ssl/src/ssl_sup.erl +++ b/lib/ssl/src/ssl_sup.erl @@ -32,14 +32,17 @@ %%%========================================================================= %%% API %%%========================================================================= + +-spec start_link() -> {ok, pid()} | ignore | {error, term()}. + start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []). %%%========================================================================= %%% Supervisor callback %%%========================================================================= -%% init([]) -> {ok, {SupFlags, [ChildSpec]}} -%% +-spec init([]) -> {ok, {SupFlags :: tuple(), [ChildSpec :: tuple()]}}. + init([]) -> %% OLD ssl - moved start to ssl.erl only if old %% ssl is acctualy run! diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl index 1d2cea6c72..c9db0d3851 100644 --- a/lib/ssl/test/erl_make_certs.erl +++ b/lib/ssl/test/erl_make_certs.erl @@ -56,7 +56,7 @@ make_cert(Opts) -> SubjectPrivateKey = get_key(Opts), {TBSCert, IssuerKey} = make_tbs(SubjectPrivateKey, Opts), - Cert = public_key:sign(TBSCert, IssuerKey), + Cert = public_key:pkix_sign(TBSCert, IssuerKey), true = verify_signature(Cert, IssuerKey, undef), %% verify that the keys where ok {Cert, encode_key(SubjectPrivateKey)}. @@ -66,8 +66,9 @@ make_cert(Opts) -> %% @end %%-------------------------------------------------------------------- write_pem(Dir, FileName, {Cert, Key = {_,_,not_encrypted}}) when is_binary(Cert) -> - ok = public_key:der_to_pem(filename:join(Dir, FileName ++ ".pem"), [{cert, Cert, not_encrypted}]), - ok = public_key:der_to_pem(filename:join(Dir, FileName ++ "_key.pem"), [Key]). + ok = ssl_test_lib:der_to_pem(filename:join(Dir, FileName ++ ".pem"), + [{'Certificate', Cert, not_encrypted}]), + ok = ssl_test_lib:der_to_pem(filename:join(Dir, FileName ++ "_key.pem"), [Key]). %%-------------------------------------------------------------------- %% @doc Creates a rsa key (OBS: for testing only) @@ -94,18 +95,14 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) -> %% @spec (::binary(), ::tuple()) -> ::boolean() %% @end %%-------------------------------------------------------------------- -verify_signature(DerEncodedCert, DerKey, KeyParams) -> +verify_signature(DerEncodedCert, DerKey, _KeyParams) -> Key = decode_key(DerKey), case Key of #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} -> - public_key:verify_signature(DerEncodedCert, - #'RSAPublicKey'{modulus=Mod, publicExponent=Exp}, - 'NULL'); + public_key:pkix_verify(DerEncodedCert, + #'RSAPublicKey'{modulus=Mod, publicExponent=Exp}); #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} -> - public_key:verify_signature(DerEncodedCert, Y, #'Dss-Parms'{p=P, q=Q, g=G}); - - _ -> - public_key:verify_signature(DerEncodedCert, Key, KeyParams) + public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}) end. %%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -132,19 +129,18 @@ decode_key(#'RSAPrivateKey'{} = Key,_) -> Key; decode_key(#'DSAPrivateKey'{} = Key,_) -> Key; -decode_key(Der = {_,_,_}, Pw) -> - {ok, Key} = public_key:decode_private_key(Der, Pw), - Key; -decode_key(FileOrDer, Pw) -> - {ok, [KeyInfo]} = public_key:pem_to_der(FileOrDer), +decode_key(PemEntry = {_,_,_}, Pw) -> + public_key:pem_entry_decode(PemEntry, Pw); +decode_key(PemBin, Pw) -> + [KeyInfo] = public_key:pem_decode(PemBin), decode_key(KeyInfo, Pw). encode_key(Key = #'RSAPrivateKey'{}) -> {ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key), - {rsa_private_key, list_to_binary(Der), not_encrypted}; + {'RSAPrivateKey', list_to_binary(Der), not_encrypted}; encode_key(Key = #'DSAPrivateKey'{}) -> {ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key), - {dsa_private_key, list_to_binary(Der), not_encrypted}. + {'DSAPrivateKey', list_to_binary(Der), not_encrypted}. make_tbs(SubjectKey, Opts) -> Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))), @@ -178,7 +174,7 @@ issuer(Opts, SubjectKey) -> end. issuer_der(Issuer) -> - {ok, Decoded} = public_key:pkix_decode_cert(Issuer, otp), + Decoded = public_key:pkix_decode_cert(Issuer, otp), #'OTPCertificate'{tbsCertificate=Tbs} = Decoded, #'OTPTBSCertificate'{subject=Subject} = Tbs, Subject. diff --git a/lib/ssl/test/make_certs.erl b/lib/ssl/test/make_certs.erl index 0cdf33c3e2..3c18a905b4 100644 --- a/lib/ssl/test/make_certs.erl +++ b/lib/ssl/test/make_certs.erl @@ -90,8 +90,10 @@ enduser(Root, OpenSSLCmd, CA, User) -> 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). + CertFileAllUsage = filename:join([UsrRoot, "cert.pem"]), + sign_req(Root, OpenSSLCmd, CA, "user_cert", ReqFile, CertFileAllUsage), + CertFileDigitalSigOnly = filename:join([UsrRoot, "digital_signature_only_cert.pem"]), + sign_req(Root, OpenSSLCmd, CA, "user_cert_digital_signature_only", ReqFile, CertFileDigitalSigOnly). collect_certs(Root, CAs, Users) -> Bins = lists:foldr( @@ -255,6 +257,7 @@ ca_cnf(CA) -> "RANDFILE = $dir/private/RAND\n" "\n" "x509_extensions = user_cert\n" + "unique_subject = no\n" "default_days = 3600\n" "default_md = sha1\n" "preserve = no\n" @@ -279,6 +282,15 @@ ca_cnf(CA) -> "issuerAltName = issuer:copy\n" "\n" + "[user_cert_digital_signature_only]\n" + "basicConstraints = CA:false\n" + "keyUsage = digitalSignature\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" diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 8a1b90ed98..53142250e8 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -233,7 +233,8 @@ all(suite) -> server_renegotiate_reused_session, client_no_wrap_sequence_number, server_no_wrap_sequence_number, extended_key_usage, validate_extensions_fun, no_authority_key_identifier, - invalid_signature_client, invalid_signature_server, cert_expired + invalid_signature_client, invalid_signature_server, cert_expired, + client_with_cert_cipher_suites_handshake ]. %% Test cases starts here. @@ -578,8 +579,8 @@ peercert(Config) when is_list(Config) -> {options, ClientOpts}]), CertFile = proplists:get_value(certfile, ServerOpts), - {ok, [{cert, BinCert, _}]} = public_key:pem_to_der(CertFile), - {ok, ErlCert} = public_key:pkix_decode_cert(BinCert, otp), + [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile), + ErlCert = public_key:pkix_decode_cert(BinCert, otp), ServerMsg = {{error, no_peercert}, {error, no_peercert}}, ClientMsg = {{ok, BinCert}, {ok, ErlCert}}, @@ -2525,35 +2526,35 @@ extended_key_usage(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), - {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile), - {ok, Key} = public_key:decode_private_key(KeyInfo), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = public_key:pem_entry_decode(KeyEntry), ServerCertFile = proplists:get_value(certfile, ServerOpts), NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"), - {ok, [{cert, ServerDerCert, _}]} = public_key:pem_to_der(ServerCertFile), - {ok, ServerOTPCert} = public_key:pkix_decode_cert(ServerDerCert, otp), + [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile), + ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp), ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']}, ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate, ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions, NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions = [ServerExtKeyUsageExt | ServerExtensions]}, - NewServerDerCert = public_key:sign(NewServerOTPTbsCert, Key), - public_key:der_to_pem(NewServerCertFile, [{cert, NewServerDerCert, not_encrypted}]), + NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]), NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], ClientCertFile = proplists:get_value(certfile, ClientOpts), NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"), - {ok, [{cert, ClientDerCert, _}]} = public_key:pem_to_der(ClientCertFile), - {ok, ClientOTPCert} = public_key:pkix_decode_cert(ClientDerCert, otp), + [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile), + ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp), ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']}, ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate, ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions, NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions = [ClientExtKeyUsageExt | ClientExtensions]}, - NewClientDerCert = public_key:sign(NewClientOTPTbsCert, Key), - public_key:der_to_pem(NewClientCertFile, [{cert, NewClientDerCert, not_encrypted}]), + NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]), NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)], {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -2621,13 +2622,13 @@ no_authority_key_identifier(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), - {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile), - {ok, Key} = public_key:decode_private_key(KeyInfo), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = public_key:pem_entry_decode(KeyEntry), CertFile = proplists:get_value(certfile, ServerOpts), NewCertFile = filename:join(PrivDir, "server/new_cert.pem"), - {ok, [{cert, DerCert, _}]} = public_key:pem_to_der(CertFile), - {ok, OTPCert} = public_key:pkix_decode_cert(DerCert, otp), + [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(CertFile), + OTPCert = public_key:pkix_decode_cert(DerCert, otp), OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate, Extensions = OTPTbsCert#'OTPTBSCertificate'.extensions, NewExtensions = delete_authority_key_extension(Extensions, []), @@ -2635,8 +2636,8 @@ no_authority_key_identifier(Config) when is_list(Config) -> test_server:format("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]), - NewDerCert = public_key:sign(NewOTPTbsCert, Key), - public_key:der_to_pem(NewCertFile, [{cert, NewDerCert, not_encrypted}]), + NewDerCert = public_key:pkix_sign(NewOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]), NewServerOpts = [{certfile, NewCertFile} | proplists:delete(certfile, ServerOpts)], {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -2679,16 +2680,16 @@ invalid_signature_server(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), KeyFile = filename:join(PrivDir, "server/key.pem"), - {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile), - {ok, Key} = public_key:decode_private_key(KeyInfo), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = public_key:pem_entry_decode(KeyEntry), ServerCertFile = proplists:get_value(certfile, ServerOpts), NewServerCertFile = filename:join(PrivDir, "server/invalid_cert.pem"), - {ok, [{cert, ServerDerCert, _}]} = public_key:pem_to_der(ServerCertFile), - {ok, ServerOTPCert} = public_key:pkix_decode_cert(ServerDerCert, otp), + [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile), + ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp), ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate, - NewServerDerCert = public_key:sign(ServerOTPTbsCert, Key), - public_key:der_to_pem(NewServerCertFile, [{cert, NewServerDerCert, not_encrypted}]), + NewServerDerCert = public_key:pkix_sign(ServerOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]), NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -2719,16 +2720,16 @@ invalid_signature_client(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), KeyFile = filename:join(PrivDir, "client/key.pem"), - {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile), - {ok, Key} = public_key:decode_private_key(KeyInfo), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = public_key:pem_entry_decode(KeyEntry), ClientCertFile = proplists:get_value(certfile, ClientOpts), NewClientCertFile = filename:join(PrivDir, "client/invalid_cert.pem"), - {ok, [{cert, ClientDerCert, _}]} = public_key:pem_to_der(ClientCertFile), - {ok, ClientOTPCert} = public_key:pkix_decode_cert(ClientDerCert, otp), + [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile), + ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp), ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate, - NewClientDerCert = public_key:sign(ClientOTPTbsCert, Key), - public_key:der_to_pem(NewClientCertFile, [{cert, NewClientDerCert, not_encrypted}]), + NewClientDerCert = public_key:pkix_sign(ClientOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]), NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)], {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -2796,13 +2797,13 @@ cert_expired(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), - {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile), - {ok, Key} = public_key:decode_private_key(KeyInfo), + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = public_key:pem_entry_decode(KeyEntry), ServerCertFile = proplists:get_value(certfile, ServerOpts), NewServerCertFile = filename:join(PrivDir, "server/expired_cert.pem"), - {ok, [{cert, DerCert, _}]} = public_key:pem_to_der(ServerCertFile), - {ok, OTPCert} = public_key:pkix_decode_cert(DerCert, otp), + [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile), + OTPCert = public_key:pkix_decode_cert(DerCert, otp), OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate, {Year, Month, Day} = date(), @@ -2825,8 +2826,8 @@ cert_expired(Config) when is_list(Config) -> [OTPTbsCert#'OTPTBSCertificate'.validity, NewValidity]), NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{validity = NewValidity}, - NewServerDerCert = public_key:sign(NewOTPTbsCert, Key), - public_key:der_to_pem(NewServerCertFile, [{cert, NewServerDerCert, not_encrypted}]), + NewServerDerCert = public_key:pkix_sign(NewOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]), NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -2849,6 +2850,39 @@ two_digits_str(N) -> lists:flatten(io_lib:format("~p", [N])). %%-------------------------------------------------------------------- + +client_with_cert_cipher_suites_handshake(doc) -> + ["Test that client with a certificate without keyEncipherment usage " + " extension can connect to a server with restricted cipher suites "]; + +client_with_cert_cipher_suites_handshake(suite) -> + []; + +client_with_cert_cipher_suites_handshake(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts_digital_signature_only, Config), + ServerOpts = ?config(server_verification_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, + send_recv_result_active, []}}, + {options, [{active, true}, + {ciphers, ssl_test_lib:rsa_non_signed_suites()} + | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + send_recv_result_active, []}}, + {options, [{active, true} + | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- send_recv_result(Socket) -> diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl index 1b8754afe9..9553241ad4 100644 --- a/lib/ssl/test/ssl_packet_SUITE.erl +++ b/lib/ssl/test/ssl_packet_SUITE.erl @@ -145,14 +145,19 @@ all(suite) -> packet_baddata_passive, packet_baddata_active, packet_size_passive, packet_size_active, packet_cdr_decode, + packet_cdr_decode_list, packet_http_decode, packet_http_decode_list, packet_http_bin_decode_multi, packet_line_decode, - packet_asn1_decode, + packet_line_decode_list, + packet_asn1_decode, + packet_asn1_decode_list, packet_tpkt_decode, + packet_tpkt_decode_list, %packet_fcgi_decode, packet_sunrm_decode, + packet_sunrm_decode_list, header_decode_one_byte, header_decode_two_bytes, header_decode_two_bytes_one_sent, @@ -1429,7 +1434,7 @@ packet_size_passive(Config) when is_list(Config) -> %%-------------------------------------------------------------------- packet_cdr_decode(doc) -> - ["Test setting the packet option {packet, cdr}"]; + ["Test setting the packet option {packet, cdr}, {mode, binary}"]; packet_cdr_decode(suite) -> []; packet_cdr_decode(Config) when is_list(Config) -> @@ -1463,8 +1468,44 @@ packet_cdr_decode(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- +packet_cdr_decode_list(doc) -> + ["Test setting the packet option {packet, cdr} {mode, list}"]; +packet_cdr_decode_list(suite) -> + []; +packet_cdr_decode_list(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + %% A valid cdr packet + Data = [71,73,79,80,1,2,2,1,0,0,0,41,0,0,0,0,0,0,0,0,0,0,0,1,78, + 69,79,0,0,0,0,2,0,10,0,0,0,0,0,0,0,0,0,18,0,0,0,0,0,0,0,4,49], + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, server_packet_decode, + [Data]}}, + {options, [{active, true}, list, + {packet, cdr}|ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, client_packet_decode, + [Data]}}, + {options, [{active, true}, {packet, cdr}, + list | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- packet_http_decode(doc) -> - ["Test setting the packet option {packet, http} {mode, binary}"]; + ["Test setting the packet option {packet, http} {mode, binary} " + "(Body will be binary http strings are lists)"]; packet_http_decode(suite) -> []; @@ -1485,7 +1526,7 @@ packet_http_decode(Config) when is_list(Config) -> {from, self()}, {mfa, {?MODULE, server_http_decode, [Response]}}, - {options, [{active, true}, binary, + {options, [{active, true},binary, {packet, http} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), @@ -1494,7 +1535,7 @@ packet_http_decode(Config) when is_list(Config) -> {from, self()}, {mfa, {?MODULE, client_http_decode, [Request]}}, - {options, [{active, true}, binary, + {options, [{active, true}, binary, {packet, http} | ClientOpts]}]), @@ -1548,7 +1589,8 @@ client_http_decode(Socket, HttpRequest) -> %%-------------------------------------------------------------------- packet_http_decode_list(doc) -> - ["Test setting the packet option {packet, http}, {mode, list}"]; + ["Test setting the packet option {packet, http}, {mode, list}" + "(Body will be litst too)"]; packet_http_decode_list(suite) -> []; packet_http_decode_list(Config) when is_list(Config) -> @@ -1697,7 +1739,7 @@ client_http_bin_decode(_, _, _) -> ok. %%-------------------------------------------------------------------- packet_line_decode(doc) -> - ["Test setting the packet option {packet, line}"]; + ["Test setting the packet option {packet, line}, {mode, binary}"]; packet_line_decode(suite) -> []; packet_line_decode(Config) when is_list(Config) -> @@ -1731,30 +1773,44 @@ packet_line_decode(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- -server_line_packet_decode(Socket, Lines) -> - receive - {ssl, Socket, <<"Line ends here.\n">>} -> ok; - Other1 -> exit({?LINE, Other1}) - end, - receive - {ssl, Socket, <<"Now it is a new line.\n">>} -> ok; - Other2 -> exit({?LINE, Other2}) - end, - ok = ssl:send(Socket, Lines). +packet_line_decode_list(doc) -> + ["Test setting the packet option {packet, line}, {mode, list}"]; +packet_line_decode_list(suite) -> + []; +packet_line_decode_list(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = lists:flatten(io_lib:format("Line ends here.~n" + "Now it is a new line.~n", [])), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, + server_line_packet_decode, + [Data]}}, + {options, [{active, true}, list, + {packet, line}|ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + client_line_packet_decode, + [Data]}}, + {options, [{active, true}, + {packet, line}, + list | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). -client_line_packet_decode(Socket, Lines) -> - <<P1:10/binary, P2/binary>> = Lines, - ok = ssl:send(Socket, P1), - ok = ssl:send(Socket, P2), - receive - {ssl, Socket, <<"Line ends here.\n">>} -> ok; - Other1 -> exit({?LINE, Other1}) - end, - receive - {ssl, Socket, <<"Now it is a new line.\n">>} -> ok; - Other2 -> exit({?LINE, Other2}) - end. %%-------------------------------------------------------------------- @@ -1770,7 +1826,7 @@ packet_asn1_decode(Config) when is_list(Config) -> File = proplists:get_value(certfile, ServerOpts), %% A valid asn1 BER packet (DER is stricter BER) - {ok,[{cert, Data, _}]} = public_key:pem_to_der(File), + [{'Certificate', Data, _}] = ssl_test_lib:pem_to_der(File), Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, {from, self()}, @@ -1794,6 +1850,44 @@ packet_asn1_decode(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- +packet_asn1_decode_list(doc) -> + ["Test setting the packet option {packet, asn1}"]; +packet_asn1_decode_list(suite) -> + []; +packet_asn1_decode_list(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + File = proplists:get_value(certfile, ServerOpts), + + %% A valid asn1 BER packet (DER is stricter BER) + [{'Certificate', BinData, _}] = ssl_test_lib:pem_to_der(File), + + Data = binary_to_list(BinData), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, server_packet_decode, + [Data]}}, + {options, [{active, true}, list, + {packet, asn1}|ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, client_packet_decode, + [Data]}}, + {options, [{active, true}, {packet, asn1}, + list | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- packet_tpkt_decode(doc) -> ["Test setting the packet option {packet, tpkt}"]; packet_tpkt_decode(suite) -> @@ -1826,6 +1920,38 @@ packet_tpkt_decode(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- +packet_tpkt_decode_list(doc) -> + ["Test setting the packet option {packet, tpkt}"]; +packet_tpkt_decode_list(suite) -> + []; +packet_tpkt_decode_list(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = binary_to_list(list_to_binary(add_tpkt_header("TPKT data"))), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, server_packet_decode, + [Data]}}, + {options, [{active, true}, list, + {packet, tpkt}|ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, client_packet_decode, + [Data]}}, + {options, [{active, true}, {packet, tpkt}, + list | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). %%-------------------------------------------------------------------- @@ -1895,6 +2021,39 @@ packet_sunrm_decode(Config) when is_list(Config) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +packet_sunrm_decode_list(doc) -> + ["Test setting the packet option {packet, sunrm}"]; +packet_sunrm_decode_list(suite) -> + []; +packet_sunrm_decode_list(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = binary_to_list(list_to_binary([<<11:32>>, "Hello world"])), + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, server_packet_decode, + [Data]}}, + {options, [{active, true}, list, + {packet, sunrm}|ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, client_packet_decode, + [Data]}}, + {options, [{active, true}, {packet, sunrm}, + list | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). %%-------------------------------------------------------------------- header_decode_one_byte(doc) -> @@ -2155,8 +2314,14 @@ server_packet_decode(Socket, Packet) -> end, ok = ssl:send(Socket, Packet). -client_packet_decode(Socket, Packet) -> +client_packet_decode(Socket, Packet) when is_binary(Packet)-> <<P1:10/binary, P2/binary>> = Packet, + client_packet_decode(Socket, P1, P2, Packet); +client_packet_decode(Socket, [Head | Tail] = Packet) -> + client_packet_decode(Socket, [Head], Tail, Packet). + +client_packet_decode(Socket, P1, P2, Packet) -> + test_server:format("Packet: ~p ~n", [Packet]), ok = ssl:send(Socket, P1), ok = ssl:send(Socket, P2), receive @@ -2176,7 +2341,7 @@ server_header_decode(Socket, Packet, Result) -> end, ok = ssl:send(Socket, Packet), receive - {ssl, Socket, Result} -> ok; + {ssl, Socket, Result} -> ok; Other2 -> exit({?LINE, Other2}) end, ok = ssl:send(Socket, Packet). @@ -2192,6 +2357,44 @@ client_header_decode(Socket, Packet, Result) -> {ssl, Socket, Result} -> ok; Other2 -> exit({?LINE, Other2}) end. + +server_line_packet_decode(Socket, Packet) when is_binary(Packet) -> + [L1, L2] = string:tokens(binary_to_list(Packet), "\n"), + server_line_packet_decode(Socket, list_to_binary(L1 ++ "\n"), list_to_binary(L2 ++ "\n"), Packet); +server_line_packet_decode(Socket, Packet) -> + [L1, L2] = string:tokens(Packet, "\n"), + server_line_packet_decode(Socket, L1 ++ "\n", L2 ++ "\n", Packet). + +server_line_packet_decode(Socket, L1, L2, Packet) -> + receive + {ssl, Socket, L1} -> ok; + Other1 -> exit({?LINE, Other1}) + end, + receive + {ssl, Socket, L2} -> ok; + Other2 -> exit({?LINE, Other2}) + end, + ok = ssl:send(Socket, Packet). + +client_line_packet_decode(Socket, Packet) when is_binary(Packet)-> + <<P1:10/binary, P2/binary>> = Packet, + [L1, L2] = string:tokens(binary_to_list(Packet), "\n"), + client_line_packet_decode(Socket, P1, P2, list_to_binary(L1 ++ "\n"), list_to_binary(L2 ++ "\n")); +client_line_packet_decode(Socket, [Head | Tail] = Packet) -> + [L1, L2] = string:tokens(Packet, "\n"), + client_line_packet_decode(Socket, [Head], Tail, L1 ++ "\n", L2 ++ "\n"). + +client_line_packet_decode(Socket, P1, P2, L1, L2) -> + ok = ssl:send(Socket, P1), + ok = ssl:send(Socket, P2), + receive + {ssl, Socket, L1} -> ok; + Other1 -> exit({?LINE, Other1}) + end, + receive + {ssl, Socket, L2} -> ok; + Other2 -> exit({?LINE, Other2}) + end. add_tpkt_header(Data) when is_binary(Data) -> L = size(Data) + 4, diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index dd0818827a..c7ff015034 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -268,6 +268,8 @@ cert_options(Config) -> "client", "cacerts.pem"]), ClientCertFile = filename:join([?config(priv_dir, Config), "client", "cert.pem"]), + ClientCertFileDigitalSignatureOnly = filename:join([?config(priv_dir, Config), + "client", "digital_signature_only_cert.pem"]), ServerCaCertFile = filename:join([?config(priv_dir, Config), "server", "cacerts.pem"]), ServerCertFile = filename:join([?config(priv_dir, Config), @@ -292,6 +294,10 @@ cert_options(Config) -> {certfile, ClientCertFile}, {keyfile, ClientKeyFile}, {ssl_imp, new}]}, + {client_verification_opts_digital_signature_only, [{cacertfile, ClientCaCertFile}, + {certfile, ClientCertFileDigitalSignatureOnly}, + {keyfile, ClientKeyFile}, + {ssl_imp, new}]}, {server_opts, [{ssl_imp, new},{reuseaddr, true}, {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]}, {server_verification_opts, [{ssl_imp, new},{reuseaddr, true}, @@ -346,9 +352,9 @@ make_dsa_cert_files(RoleStr, Config) -> KeyFile = filename:join([?config(priv_dir, Config), RoleStr, "dsa_key.pem"]), - public_key:der_to_pem(CaCertFile, [{cert, CaCert, not_encrypted}]), - public_key:der_to_pem(CertFile, [{cert, Cert, not_encrypted}]), - public_key:der_to_pem(KeyFile, [CertKey]), + der_to_pem(CaCertFile, [{'Certificate', CaCert, not_encrypted}]), + der_to_pem(CertFile, [{'Certificate', Cert, not_encrypted}]), + der_to_pem(KeyFile, [CertKey]), {CaCertFile, CertFile, KeyFile}. start_upgrade_server(Args) -> @@ -571,6 +577,14 @@ rsa_suites() -> end, ssl:cipher_suites()). +rsa_non_signed_suites() -> + lists:filter(fun({rsa, _, _}) -> + true; + (_) -> + false + end, + ssl:cipher_suites()). + dsa_suites() -> lists:filter(fun({dhe_dss, _, _}) -> true; @@ -601,3 +615,11 @@ openssl_dsa_suites() -> true end end, Ciphers). + +pem_to_der(File) -> + {ok, PemBin} = file:read_file(File), + public_key:pem_decode(PemBin). + +der_to_pem(File, Entries) -> + PemBin = public_key:pem_encode(Entries), + file:write_file(File, PemBin). diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk index 254ee8b986..6c40a4529c 100644 --- a/lib/ssl/vsn.mk +++ b/lib/ssl/vsn.mk @@ -18,46 +18,3 @@ # SSL_VSN = 4.0.1 - -TICKETS = OTP-8721 - -#TICKETS_4.0 = OTP-8587\ -# OTP-8695 - -#TICKETS_3.11.1 = OTP-8679 \ -# OTP-7047 \ -# OTP-7049 \ -# OTP-8568 \ -# OTP-8588 - -#TICKETS_3.11 = OTP-8517 \ -# OTP-7046 \ -# OTP-8557 \ -# OTP-8560 \ -# OTP-8545 \ -# OTP-8554 - -#TICKETS_3.10.9 = OTP-8510 - -#TICKETS_3.10.8 = OTP-8372 OTP-8441 OTP-8459 -#TICKETS_3.10.7 = OTP-8260 OTP-8218 OTP-8250 - -#TICKETS_3.10.6 = OTP-8275 - -#TICKETS_3.10.5 = OTP-8224 OTP-8244 - -#TICKETS_3.10.4 = OTP-8137 - -#TICKETS_3.10.3 = OTP-8011 -#TICKETS_3.10.2 = OTP-7963 - -# TICKETS_3.10.1 = OTP-7878 \ -# OTP-7656 \ -# OTP-7870 \ -# OTP-7871 - -# TICKETS_3.10 = OTP-7258 \ -# OTP-6894 \ -# OTP-7037 \ -# OTP-7039 \ -# OTP-7150 diff --git a/lib/stdlib/doc/src/dets.xml b/lib/stdlib/doc/src/dets.xml index 8d1398d3b7..ad100d2cf5 100644 --- a/lib/stdlib/doc/src/dets.xml +++ b/lib/stdlib/doc/src/dets.xml @@ -109,7 +109,7 @@ bool() = true | false file() = string() int() = integer() >= 0 keypos() = integer() >= 1 -name() = atom() | ref() +name() = atom() | reference() no_slots() = integer() >= 0 | default object() = tuple() object_cont() = tuple() @@ -759,7 +759,7 @@ ok <fsummary>Open an existing Dets table.</fsummary> <type> <v>FileName = file()</v> - <v>Reference = ref()</v> + <v>Reference = reference()</v> </type> <desc> <p>Opens an existing table. If the table has not been properly diff --git a/lib/stdlib/doc/src/io_protocol.xml b/lib/stdlib/doc/src/io_protocol.xml index b52e862a5c..a97d996d98 100644 --- a/lib/stdlib/doc/src/io_protocol.xml +++ b/lib/stdlib/doc/src/io_protocol.xml @@ -79,7 +79,7 @@ sends the reply to.</item> io_reply. The io-module in the Erlang standard library simply uses the pid() of the io_server as the ReplyAs datum, but a more complicated client could have several outstanding io-requests to the same server and -would then use i.e. a ref() or something else to differentiate among +would then use i.e. a reference() or something else to differentiate among the incoming io_reply's. The ReplyAs element should be considered opaque by the io_server. Note that the pid() of the server is not explicitly present in the io_reply. The reply can be sent from any diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl index 1514414e48..5c52dfcbf0 100644 --- a/lib/stdlib/src/otp_internal.erl +++ b/lib/stdlib/src/otp_internal.erl @@ -361,6 +361,12 @@ obsolete_1(erlang, concat_binary, 1) -> obsolete_1(ssl, peercert, 2) -> {deprecated,"deprecated (will be removed in R15A); use ssl:peercert/1 and public_key:pkix_decode_cert/2 instead"}; +%% Added in R14B. +obsolete_1(public_key, pem_to_der, 1) -> + {deprecated,"deprecated (will be removed in R15A); use file:read_file/1 and public_key:pem_decode/1"}; +obsolete_1(public_key, decode_private_key, A) when A =:= 1; A =:= 2 -> + {deprecated,{public_key,pem_entry_decode,1},"R15A"}; + obsolete_1(_, _, _) -> no. diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl index 6501e05a6e..c4d1bd1d2f 100644 --- a/lib/tools/src/cover.erl +++ b/lib/tools/src/cover.erl @@ -2174,6 +2174,8 @@ escape_lt_and_gt1([$<|T],Acc) -> escape_lt_and_gt1(T,[$;,$t,$l,$&|Acc]); escape_lt_and_gt1([$>|T],Acc) -> escape_lt_and_gt1(T,[$;,$t,$g,$&|Acc]); +escape_lt_and_gt1([$&|T],Acc) -> + escape_lt_and_gt1(T,[$;,$p,$m,$a,$&|Acc]); escape_lt_and_gt1([],Acc) -> lists:reverse(Acc); escape_lt_and_gt1([H|T],Acc) -> diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp index 528a08e654..6d2926ce4e 100644 --- a/lib/wx/c_src/wxe_impl.cpp +++ b/lib/wx/c_src/wxe_impl.cpp @@ -411,7 +411,7 @@ void WxeApp::dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process) if(event->caller == process || // Callbacks from CB process only event->op == WXE_CB_START || // Recursive event callback allow // Allow connect_cb during CB i.e. msg from wxe_server. - event->caller == memenv->owner) + (memenv && event->caller == memenv->owner)) { switch(event->op) { case WXE_BATCH_END: @@ -669,7 +669,7 @@ void WxeApp::clearPtr(void * ptr) { send_msg("debug", &msg); } - if(refd->pid != -1) { + if(((int) refd->pid) != -1) { // Send terminate pid to owner wxeReturn rt = wxeReturn(WXE_DRV_PORT,refd->memenv->owner, false); rt.addAtom("_wxe_destroy_"); diff --git a/lib/wx/vsn.mk b/lib/wx/vsn.mk index 4ed22d2256..c3ad3920a4 100644 --- a/lib/wx/vsn.mk +++ b/lib/wx/vsn.mk @@ -1,9 +1 @@ WX_VSN = 0.98.6 - -TICKETS = OTP-8656 - -TICKETS_0.98.5 = OTP-8330 OTP-8461 OTP-8408 OTP-8455 OTP-8462 -TICKETS_0.98.4 = OTP-8243 OTP-8250 OTP-8292 -TICKETS_0.98.3 = OTP-8138 OTP-8126 OTP-8083 -TICKETS_0.98.2 = OTP-7943 -TICKETS_0.98.1 = OTP-7875
\ No newline at end of file diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk index aee7546c3c..2239604b59 100644 --- a/lib/xmerl/vsn.mk +++ b/lib/xmerl/vsn.mk @@ -18,113 +18,3 @@ # XMERL_VSN = 1.2.5 - - -TICKETS = \ - OTP-8537 \ - OTP-8599 - -TICKETS_1.2.5 = \ - OTP-8537 - -TICKETS_1.2.4 = \ - OTP-8343 - -TICKETS_1.2.3 = \ - OTP-8251 \ - OTP-8252 \ - OTP-8253 - -TICKETS_1.2.2 = \ - OTP-8213 \ - OTP-8214 - -TICKETS_1.2.1 = \ - OTP-8084 \ - OTP-8153 \ - OTP-8156 - -TICKETS_1.2 = \ - OTP-6635 - -TICKETS_1.1.12 = \ - OTP-7847 - -TICKETS_1.1.11 = \ - OTP-7736 - -TICKETS_1.1.10 = \ - OTP-6053 \ - OTP-6873 \ - OTP-7430 \ - OTP-7473 \ - OTP-7496 - -TICKETS_1.1.9 = \ - OTP-5998 \ - OTP-6947 \ - OTP-7288 - -TICKETS_1.1.8 = \ - OTP-7211 \ - OTP-7214 - -TICKETS_1.1.7 = \ - OTP-7190 - -TICKETS_1.1.6 = \ - OTP-6773 \ - OTP-6777 \ - OTP-6877 \ - OTP-6910 - -TICKETS_1.1.5 = \ - OTP-6720 \ - OTP-6739 \ - OTP-6752 - -TICKETS_1.1.4 = \ - OTP-6679 - -TICKETS_1.1.3 = \ - OTP-6599 - -TICKETS_1.1.2 = \ - OTP-6507 \ - OTP-6460 - -TICKETS_1.1.1 = \ - OTP-6402 - -TICKETS_1.1 = \ - OTP-6043 \ - OTP-6099 \ - OTP-6401 - -TICKETS_1.0.5 = \ - - -TICKETS_1.0.4 = \ - OTP-5599 \ - OTP-5718 \ - OTP-5734 \ - OTP-5895 \ - OTP-5902 \ - OTP-5905 - -TICKETS_1.0.3 = \ - OTP-5587 - -TICKETS_1.0.2 = \ - OTP-5498 \ - OTP-5500 \ - OTP-5531 - -TICKETS_1.0.1 = \ - OTP-5268 \ - OTP-5301 \ - OTP-5407 - -TICKETS_1.0 = \ - OTP-5174 \ - |