aboutsummaryrefslogblamecommitdiffstats
path: root/lib/public_key/test/public_key_SUITE.erl
blob: 6a3d6bfcf5203c69d4654b0d64cf793cf13c7952 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                   


                                                        




                                                                      
  



                                                                         
  








                                                           


                                                         










































































                                                                       
         
                 




                         








                                                                      
                                   

                                          














                                                                                                





                                                                                
                                                         


                                                                        
                                      











                                                                              
                                                 

                                                                     
                                                                       
                                                                     


                                                                               
    


                                                                                



























                                                                                           











                                                                   
       





















                                                                                  
    








                                                                                       
 
















                                                                                                     
 












                                                                                          
 





                                                                                                            
 


                                                                             
 

                                                                  
 


                                                                                               
 





                                                                                                         
 




                                            
       



















                                                                                                     
    

                                                                                                                
    

                                                                               
 



                                                                                                              
    
                                                                                                       
 

                                               
%%
%% %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.