%% %% %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% %% %% -module(public_key_SUITE). %% Note: This directive should only be used in test suites. -compile(export_all). -include_lib("test_server/include/test_server.hrl"). -include_lib("test_server/include/test_server_line.hrl"). -include("public_key.hrl"). -define(TIMEOUT, 120000). % 2 min %% Test server callback functions %%-------------------------------------------------------------------- %% Function: init_per_suite(Config) -> Config %% Config - [tuple()] %% A list of key/value pairs, holding the test case configuration. %% Description: Initialization before the whole suite %% %% Note: This function is free to add any key/value pairs to the Config %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- init_per_suite(Config) -> crypto:start(), Config. %%-------------------------------------------------------------------- %% Function: end_per_suite(Config) -> _ %% Config - [tuple()] %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after the whole suite %%-------------------------------------------------------------------- end_per_suite(_Config) -> crypto:stop(). %%-------------------------------------------------------------------- %% Function: init_per_testcase(TestCase, Config) -> Config %% Case - atom() %% Name of the test case that is about to be run. %% Config - [tuple()] %% A list of key/value pairs, holding the test case configuration. %% %% Description: Initialization before each test case %% %% Note: This function is free to add any key/value pairs to the Config %% variable, but should NOT alter/remove any existing entries. %% Description: Initialization before each test case %%-------------------------------------------------------------------- init_per_testcase(_TestCase, Config0) -> Config = lists:keydelete(watchdog, 1, Config0), Dog = test_server:timetrap(?TIMEOUT), [{watchdog, Dog} | Config]. %%-------------------------------------------------------------------- %% Function: end_per_testcase(TestCase, Config) -> _ %% Case - atom() %% Name of the test case that is about to be run. %% Config - [tuple()] %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after each test case %%-------------------------------------------------------------------- end_per_testcase(_TestCase, Config) -> Dog = ?config(watchdog, Config), case Dog of undefined -> ok; _ -> test_server:timetrap_cancel(Dog) end. %%-------------------------------------------------------------------- %% Function: all(Clause) -> TestCases %% Clause - atom() - suite | doc %% TestCases - [Case] %% Case - atom() %% Name of a test case. %% Description: Returns a list of all test cases in this test suite %%-------------------------------------------------------------------- all(doc) -> ["Test the public_key rsa functionality"]; all(suite) -> [app, dh, pem_to_der, decode_private_key, encrypt_decrypt, sign_verify, pkix, pkix_path_validation ]. %% Test cases starts here. %%-------------------------------------------------------------------- app(doc) -> "Test that the public_key app file is ok"; 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) -> []; dh(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. 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), {ok, Certs} = public_key:pem_to_der(filename:join(Datadir, "wcacerts.pem")), {ok, DSAKey} = public_key:pem_to_der(filename:join(Datadir, "wdsa.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")), {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"), ok. %%-------------------------------------------------------------------- encrypt_decrypt(doc) -> [""]; encrypt_decrypt(suite) -> []; encrypt_decrypt(Config) when is_list(Config) -> {PrivateKey, _DerKey} = pkey_test:gen_rsa(64), #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} = PrivateKey, PublicKey = #'RSAPublicKey'{modulus=Mod, publicExponent=Exp}, Msg = list_to_binary(lists:duplicate(5, "Foo bar 100")), RsaEncrypted = public_key:encrypt_private(Msg, PrivateKey), Msg = public_key:decrypt_public(RsaEncrypted, PublicKey), Msg = public_key:decrypt_public(RsaEncrypted, PrivateKey), RsaEncrypted2 = public_key:encrypt_public(Msg, PublicKey), RsaEncrypted3 = public_key:encrypt_public(Msg, PrivateKey), Msg = public_key:decrypt_private(RsaEncrypted2, PrivateKey), Msg = public_key:decrypt_private(RsaEncrypted3, PrivateKey), ok. %%-------------------------------------------------------------------- sign_verify(doc) -> ["Checks that we can sign and verify signatures."]; 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), 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), {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}), %% 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), %% 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), #'DSAPrivateKey'{p=P1, q=Q1, g=G1, y=Y1, x=_X1} = DSAPrivateKey, DSASign = public_key:sign(Msg, 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), 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), false = public_key:pkix_is_fixed_dh_cert(CertDer) end, [TestTransform(Cert) || Cert <- Certs0 ++ Certs1], 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), 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), ok. pkix_path_validation(doc) -> "Misc pkix tests not covered elsewhere"; pkix_path_validation(suite) -> []; pkix_path_validation(Config) when is_list(Config) -> CaK = {Trusted,_} = pkey_test:make_cert([{key, dsa}, {subject, [ {name, "Public Key"}, {?'id-at-name', {printableString, "public_key"}}, {?'id-at-pseudonym', {printableString, "pubkey"}}, {city, "Stockholm"}, {country, "SE"}, {org, "erlang"}, {org_unit, "testing dep"} ]} ]), ok = pkey_test:write_pem("/tmp", "cacert", CaK), CertK1 = {Cert1, _} = pkey_test:make_cert([{issuer, CaK}]), CertK2 = {Cert2,_} = pkey_test:make_cert([{issuer, CertK1}, {digest, md5}, {extensions, false}]), ok = pkey_test:write_pem("/tmp", "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}]), {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}]}]), {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}]), % test_server:format("PV ~p ~n", [Result]), ok.