aboutsummaryrefslogtreecommitdiffstats
path: root/lib/public_key/test
diff options
context:
space:
mode:
Diffstat (limited to 'lib/public_key/test')
-rw-r--r--lib/public_key/test/Makefile6
-rw-r--r--lib/public_key/test/pkey_test.erl412
-rw-r--r--lib/public_key/test/public_key.cover2
-rw-r--r--lib/public_key/test/public_key_SUITE.erl238
4 files changed, 580 insertions, 78 deletions
diff --git a/lib/public_key/test/Makefile b/lib/public_key/test/Makefile
index c7215020c7..5544339ff2 100644
--- a/lib/public_key/test/Makefile
+++ b/lib/public_key/test/Makefile
@@ -28,6 +28,7 @@ INCLUDES= -I. -I ../include
# ----------------------------------------------------
MODULES= \
+ pkey_test \
public_key_SUITE \
pkits_SUITE
@@ -40,6 +41,9 @@ TARGET_FILES= \
SPEC_FILES = public_key.spec
+COVER_FILE = public_key.cover
+
+
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -74,7 +78,7 @@ release_spec: opt
release_tests_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(SPEC_FILES) $(ERL_FILES) $(HRL_FILES)$(RELSYSDIR)
+ $(INSTALL_DATA) $(SPEC_FILES) $(ERL_FILES) $(COVER_FILE) $(HRL_FILES) $(RELSYSDIR)
$(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)
chmod -f -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
diff --git a/lib/public_key/test/pkey_test.erl b/lib/public_key/test/pkey_test.erl
new file mode 100644
index 0000000000..9d596eee4f
--- /dev/null
+++ b/lib/public_key/test/pkey_test.erl
@@ -0,0 +1,412 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+
+%% Create test certificates
+
+-module(pkey_test).
+-include_lib("public_key/include/public_key.hrl").
+
+-export([make_cert/1, gen_rsa/1, verify_signature/3, write_pem/3]).
+-compile(export_all).
+
+%%--------------------------------------------------------------------
+%% @doc Create and return a der encoded certificate
+%% Option Default
+%% -------------------------------------------------------
+%% digest sha1
+%% validity {date(), date() + week()}
+%% version 3
+%% subject [] list of the following content
+%% {name, Name}
+%% {email, Email}
+%% {city, City}
+%% {state, State}
+%% {org, Org}
+%% {org_unit, OrgUnit}
+%% {country, Country}
+%% {serial, Serial}
+%% {title, Title}
+%% {dnQualifer, DnQ}
+%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created)
+%% (obs IssuerKey migth be {Key, Password}
+%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key
+%%
+%%
+%% (OBS: The generated keys are for testing only)
+%% @spec ([{::atom(), ::term()}]) -> {Cert::binary(), Key::binary()}
+%% @end
+%%--------------------------------------------------------------------
+
+make_cert(Opts) ->
+ SubjectPrivateKey = get_key(Opts),
+ {TBSCert, IssuerKey} = make_tbs(SubjectPrivateKey, Opts),
+ Cert = public_key:sign(TBSCert, IssuerKey),
+ true = verify_signature(Cert, IssuerKey, undef), %% verify that the keys where ok
+ {Cert, encode_key(SubjectPrivateKey)}.
+
+%%--------------------------------------------------------------------
+%% @doc Writes pem files in Dir with FileName ++ ".pem" and FileName ++ "_key.pem"
+%% @spec (::string(), ::string(), {Cert,Key}) -> ok
+%% @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]).
+
+%%--------------------------------------------------------------------
+%% @doc Creates a rsa key (OBS: for testing only)
+%% the size are in bytes
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
+%%--------------------------------------------------------------------
+gen_rsa(Size) when is_integer(Size) ->
+ Key = gen_rsa2(Size),
+ {Key, encode_key(Key)}.
+
+%%--------------------------------------------------------------------
+%% @doc Creates a dsa key (OBS: for testing only)
+%% the sizes are in bytes
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
+%%--------------------------------------------------------------------
+gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
+ Key = gen_dsa2(LSize, NSize),
+ {Key, encode_key(Key)}.
+
+%%--------------------------------------------------------------------
+%% @doc Verifies cert signatures
+%% @spec (::binary(), ::tuple()) -> ::boolean()
+%% @end
+%%--------------------------------------------------------------------
+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');
+ #'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)
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+get_key(Opts) ->
+ case proplists:get_value(key, Opts) of
+ undefined -> make_key(rsa, Opts);
+ rsa -> make_key(rsa, Opts);
+ dsa -> make_key(dsa, Opts);
+ Key ->
+ Password = proplists:get_value(password, Opts, no_passwd),
+ decode_key(Key, Password)
+ end.
+
+decode_key({Key, Pw}) ->
+ decode_key(Key, Pw);
+decode_key(Key) ->
+ decode_key(Key, no_passwd).
+
+
+decode_key(#'RSAPublicKey'{} = Key,_) ->
+ Key;
+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(KeyInfo, Pw).
+
+encode_key(Key = #'RSAPrivateKey'{}) ->
+ {ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key),
+ {rsa_private_key, 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}.
+
+make_tbs(SubjectKey, Opts) ->
+ Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
+ {Issuer, IssuerKey} = issuer(Opts, SubjectKey),
+
+ {Algo, Parameters} = sign_algorithm(IssuerKey, Opts),
+
+ SignAlgo = #'SignatureAlgorithm'{algorithm = Algo,
+ parameters = Parameters},
+
+ {#'OTPTBSCertificate'{serialNumber = trunc(random:uniform()*100000000)*10000 + 1,
+ signature = SignAlgo,
+ issuer = Issuer,
+ validity = validity(Opts),
+ subject = subject(proplists:get_value(subject, Opts),false),
+ subjectPublicKeyInfo = publickey(SubjectKey),
+ version = Version,
+ extensions = extensions(Opts)
+ }, IssuerKey}.
+
+issuer(Opts, SubjectKey) ->
+ IssuerProp = proplists:get_value(issuer, Opts, true),
+ case IssuerProp of
+ true -> %% Self signed
+ {subject(proplists:get_value(subject, Opts), true), SubjectKey};
+ {Issuer, IssuerKey} when is_binary(Issuer) ->
+ {issuer_der(Issuer), decode_key(IssuerKey)};
+ {File, IssuerKey} when is_list(File) ->
+ {ok, [{cert, Cert, _}|_]} = public_key:pem_to_der(File),
+ {issuer_der(Cert), decode_key(IssuerKey)}
+ end.
+
+issuer_der(Issuer) ->
+ {ok, Decoded} = public_key:pkix_decode_cert(Issuer, otp),
+ #'OTPCertificate'{tbsCertificate=Tbs} = Decoded,
+ #'OTPTBSCertificate'{subject=Subject} = Tbs,
+ Subject.
+
+subject(undefined, IsCA) ->
+ User = if IsCA -> "CA"; true -> os:getenv("USER") end,
+ Opts = [{email, User ++ "@erlang.org"},
+ {name, User},
+ {city, "Stockholm"},
+ {country, "SE"},
+ {org, "erlang"},
+ {org_unit, "testing dep"}],
+ subject(Opts);
+subject(Opts, _) ->
+ subject(Opts).
+
+subject(SubjectOpts) when is_list(SubjectOpts) ->
+ Encode = fun(Opt) ->
+ {Type,Value} = subject_enc(Opt),
+ [#'AttributeTypeAndValue'{type=Type, value=Value}]
+ end,
+ {rdnSequence, [Encode(Opt) || Opt <- SubjectOpts]}.
+
+%% Fill in the blanks
+subject_enc({name, Name}) -> {?'id-at-commonName', {printableString, Name}};
+subject_enc({email, Email}) -> {?'id-emailAddress', Email};
+subject_enc({city, City}) -> {?'id-at-localityName', {printableString, City}};
+subject_enc({state, State}) -> {?'id-at-stateOrProvinceName', {printableString, State}};
+subject_enc({org, Org}) -> {?'id-at-organizationName', {printableString, Org}};
+subject_enc({org_unit, OrgUnit}) -> {?'id-at-organizationalUnitName', {printableString, OrgUnit}};
+subject_enc({country, Country}) -> {?'id-at-countryName', Country};
+subject_enc({serial, Serial}) -> {?'id-at-serialNumber', Serial};
+subject_enc({title, Title}) -> {?'id-at-title', {printableString, Title}};
+subject_enc({dnQualifer, DnQ}) -> {?'id-at-dnQualifier', DnQ};
+subject_enc(Other) -> Other.
+
+
+extensions(Opts) ->
+ case proplists:get_value(extensions, Opts, []) of
+ false ->
+ asn1_NOVALUE;
+ Exts ->
+ lists:flatten([extension(Ext) || Ext <- default_extensions(Exts)])
+ end.
+
+default_extensions(Exts) ->
+ Def = [{key_usage,undefined},
+ {subject_altname, undefined},
+ {issuer_altname, undefined},
+ {basic_constraints, default},
+ {name_constraints, undefined},
+ {policy_constraints, undefined},
+ {ext_key_usage, undefined},
+ {inhibit_any, undefined},
+ {auth_key_id, undefined},
+ {subject_key_id, undefined},
+ {policy_mapping, undefined}],
+ Filter = fun({Key, _}, D) -> lists:keydelete(Key, 1, D) end,
+ Exts ++ lists:foldl(Filter, Def, Exts).
+
+extension({_, undefined}) -> [];
+extension({basic_constraints, Data}) ->
+ case Data of
+ default ->
+ #'Extension'{extnID = ?'id-ce-basicConstraints',
+ extnValue = #'BasicConstraints'{cA=true},
+ critical=true};
+ false ->
+ [];
+ Len when is_integer(Len) ->
+ #'Extension'{extnID = ?'id-ce-basicConstraints',
+ extnValue = #'BasicConstraints'{cA=true, pathLenConstraint=Len},
+ critical=true};
+ _ ->
+ #'Extension'{extnID = ?'id-ce-basicConstraints',
+ extnValue = Data}
+ end;
+extension({Id, Data, Critical}) ->
+ #'Extension'{extnID = Id, extnValue = Data, critical = Critical}.
+
+
+publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) ->
+ Public = #'RSAPublicKey'{modulus=N, publicExponent=E},
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?rsaEncryption, parameters='NULL'},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
+ subjectPublicKey = Public};
+publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa',
+ parameters=#'Dss-Parms'{p=P, q=Q, g=G}},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
+
+validity(Opts) ->
+ 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,
+ #'Validity'{notBefore={generalTime, Format(DefFrom)},
+ notAfter ={generalTime, Format(DefTo)}}.
+
+sign_algorithm(#'RSAPrivateKey'{}, Opts) ->
+ Type = case proplists:get_value(digest, Opts, sha1) of
+ sha1 -> ?'sha1WithRSAEncryption';
+ sha512 -> ?'sha512WithRSAEncryption';
+ sha384 -> ?'sha384WithRSAEncryption';
+ sha256 -> ?'sha256WithRSAEncryption';
+ md5 -> ?'md5WithRSAEncryption';
+ md2 -> ?'md2WithRSAEncryption'
+ end,
+ {Type, 'NULL'};
+sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) ->
+ {?'id-dsa-with-sha1', #'Dss-Parms'{p=P, q=Q, g=G}}.
+
+make_key(rsa, _Opts) ->
+ %% (OBS: for testing only)
+ gen_rsa2(64);
+make_key(dsa, _Opts) ->
+ gen_dsa2(128, 20). %% Bytes i.e. {1024, 160}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% RSA key generation (OBS: for testing only)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(SMALL_PRIMES, [65537,97,89,83,79,73,71,67,61,59,53,
+ 47,43,41,37,31,29,23,19,17,13,11,7,5,3]).
+
+gen_rsa2(Size) ->
+ P = prime(Size),
+ Q = prime(Size),
+ N = P*Q,
+ Tot = (P - 1) * (Q - 1),
+ [E|_] = lists:dropwhile(fun(Candidate) -> (Tot rem Candidate) == 0 end, ?SMALL_PRIMES),
+ {D1,D2} = extended_gcd(E, Tot),
+ D = erlang:max(D1,D2),
+ case D < E of
+ true ->
+ gen_rsa2(Size);
+ false ->
+ {Co1,Co2} = extended_gcd(Q, P),
+ Co = erlang:max(Co1,Co2),
+ #'RSAPrivateKey'{version = 'two-prime',
+ modulus = N,
+ publicExponent = E,
+ privateExponent = D,
+ prime1 = P,
+ prime2 = Q,
+ exponent1 = D rem (P-1),
+ exponent2 = D rem (Q-1),
+ coefficient = Co
+ }
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% DSA key generation (OBS: for testing only)
+%% See http://en.wikipedia.org/wiki/Digital_Signature_Algorithm
+%% and the fips_186-3.pdf
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+gen_dsa2(LSize, NSize) ->
+ Q = prime(NSize), %% Choose N-bit prime Q
+ X0 = prime(LSize),
+ P0 = prime((LSize div 2) +1),
+
+ %% Choose L-bit prime modulus P such that p–1 is a multiple of q.
+ case dsa_search(X0 div (2*Q*P0), P0, Q, 1000) of
+ error ->
+ gen_dsa2(LSize, NSize);
+ P ->
+ G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
+ %% such that This may be done by setting g = h^(p–1)/q mod p, commonly h=2 is used.
+
+ X = prime(20), %% Choose x by some random method, where 0 < x < q.
+ Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p.
+
+ #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
+ end.
+
+%% See fips_186-3.pdf
+dsa_search(T, P0, Q, Iter) when Iter > 0 ->
+ P = 2*T*Q*P0 + 1,
+ case is_prime(crypto:mpint(P), 50) of
+ true -> P;
+ false -> dsa_search(T+1, P0, Q, Iter-1)
+ end;
+dsa_search(_,_,_,_) ->
+ error.
+
+
+%%%%%%% Crypto Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+prime(ByteSize) ->
+ Rand = odd_rand(ByteSize),
+ crypto:erlint(prime_odd(Rand, 0)).
+
+prime_odd(Rand, N) ->
+ case is_prime(Rand, 50) of
+ true ->
+ Rand;
+ false ->
+ NotPrime = crypto:erlint(Rand),
+ prime_odd(crypto:mpint(NotPrime+2), N+1)
+ end.
+
+%% see http://en.wikipedia.org/wiki/Fermat_primality_test
+is_prime(_, 0) -> true;
+is_prime(Candidate, Test) ->
+ CoPrime = odd_rand(<<0,0,0,4, 10000:32>>, Candidate),
+ case crypto:mod_exp(CoPrime, Candidate, Candidate) of
+ CoPrime -> is_prime(Candidate, Test-1);
+ _ -> false
+ end.
+
+odd_rand(Size) ->
+ Min = 1 bsl (Size*8-1),
+ Max = (1 bsl (Size*8))-1,
+ odd_rand(crypto:mpint(Min), crypto:mpint(Max)).
+
+odd_rand(Min,Max) ->
+ Rand = <<Sz:32, _/binary>> = crypto:rand_uniform(Min,Max),
+ BitSkip = (Sz+4)*8-1,
+ case Rand of
+ Odd = <<_:BitSkip, 1:1>> -> Odd;
+ Even = <<_:BitSkip, 0:1>> ->
+ crypto:mpint(crypto:erlint(Even)+1)
+ end.
+
+extended_gcd(A, B) ->
+ case A rem B of
+ 0 ->
+ {0, 1};
+ N ->
+ {X, Y} = extended_gcd(B, N),
+ {Y, X-Y*(A div B)}
+ end.
diff --git a/lib/public_key/test/public_key.cover b/lib/public_key/test/public_key.cover
new file mode 100644
index 0000000000..8477c76ef6
--- /dev/null
+++ b/lib/public_key/test/public_key.cover
@@ -0,0 +1,2 @@
+
+{exclude, ['OTP-PUB-KEY']}. \ No newline at end of file
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 8cc36e490d..6a3d6bfcf5 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -101,14 +101,13 @@ all(doc) ->
all(suite) ->
[app,
+ dh,
pem_to_der,
- decode_private_key
-%% encrypt_decrypt,
-%% rsa_verify
-%% dsa_verify_sign,
-%% pkix_encode_decode,
-%% pkix_verify_sign,
-%% pkix_path_validation
+ decode_private_key,
+ encrypt_decrypt,
+ sign_verify,
+ pkix,
+ pkix_path_validation
].
%% Test cases starts here.
@@ -118,20 +117,35 @@ app(doc) ->
"Test that the public_key app file is ok";
app(suite) ->
[];
-app(Config) when list(Config) ->
+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,[{dsa_private_key, _, not_encrypted}]} =
+ {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, _, _}]} =
+ {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"),
@@ -144,12 +158,18 @@ pem_to_der(Config) when is_list(Config) ->
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,[{cert, _, _}, {cert, _, _}]} =
+ {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, 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) ->
@@ -178,84 +198,148 @@ encrypt_decrypt(doc) ->
encrypt_decrypt(suite) ->
[];
encrypt_decrypt(Config) when is_list(Config) ->
- RSAPrivateKey = #'RSAPrivateKey'{publicExponent = 17,
- modulus = 3233,
- privateExponent = 2753,
- prime1 = 61,
- prime2 = 53,
- version = 'two-prime'},
- Msg = <<0,123>>,
- {ok, Encrypted} = public_key:encrypt(Msg, RSAPrivateKey, [{block_type, 2}]),
- test_server:format("Expected 855, Encrypted ~p ~n", [Encrypted]),
+ {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),
-%% Datadir = ?config(data_dir, Config),
-%% {ok,[{rsa_private_key, EncKey}]} =
-%% public_key:pem_to_der(filename:join(Datadir, "server_key.pem")),
-%% {ok, Key} = public_key:decode_private_key(EncKey, rsa),
-%% RSAPublicKey = #'RSAPublicKey'{publicExponent =
-%% Key#'RSAPrivateKey'.publicExponent,
-%% modulus = Key#'RSAPrivateKey'.modulus},
-%% {ok, Msg} = file:read_file(filename:join(Datadir, "msg.txt")),
-%% Hash = crypto:sha(Msg),
-%% {ok, Encrypted} = public_key:encrypt(Hash, Key, [{block_type, 2}]),
-%% test_server:format("Encrypted ~p", [Encrypted]),
-%% {ok, Decrypted} = public_key:decrypt(Encrypted,
-%% RSAPublicKey, [{block_type, 1}]),
-%% test_server:format("Encrypted ~p", [Decrypted]),
-%% true = Encrypted == Decrypted.
-
-%%--------------------------------------------------------------------
-rsa_verify(doc) ->
- ["Cheks that we can verify an rsa signature."];
-rsa_verify(suite) ->
+ ok.
+
+pkix_path_validation(doc) ->
+ "Misc pkix tests not covered elsewhere";
+pkix_path_validation(suite) ->
[];
-rsa_verify(Config) when is_list(Config) ->
- Datadir = ?config(data_dir, Config),
-
- {ok,[{cert, DerCert}]} =
- public_key:pem_to_der(filename:join(Datadir, "server_cert.pem")),
+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], []),
- {ok, OTPCert} = public_key:pkix_decode_cert(DerCert, otp),
+ {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}]),
- {0, Signature} = OTPCert#'Certificate'.signature,
- TBSCert = OTPCert#'Certificate'.tbsCertificate,
+ {ok, _} = public_key:pkix_path_validation(Trusted, [Cert1, Cert2], []),
+ {error, issuer_not_found} = public_key:pkix_issuer_id(Cert2, other),
- #'TBSCertificate'{subjectPublicKeyInfo = Info} = TBSCert,
+ 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], []),
- #'SubjectPublicKeyInfo'{subjectPublicKey = RSAPublicKey} = Info,
-
- EncTBSCert = encoded_tbs_cert(DerCert),
- Digest = crypto:sha(EncTBSCert),
-
- public_key:verify_signature(Digest, Signature, RSAPublicKey).
-
-
-%% Signature is generated in the following way (in datadir):
-%% openssl dgst -sha1 -binary -out rsa_signature -sign server_key.pem msg.txt
-%%{ok, Signature} = file:read_file(filename:join(Datadir, "rsa_signature")),
-%%{ok, Signature} = file:read_file(filename:join(Datadir, "rsa_signature")),
-%% {ok, Msg} = file:read_file(filename:join(Datadir, "msg.txt")),
-%% Digest = crypto:sha(Msg),
-%% {ok,[{rsa_private_key, EncKey}]} =
-%% public_key:pem_to_der(filename:join(Datadir, "server_key.pem")),
-%% {ok, Key} = public_key:decode_private_key(EncKey, rsa),
-%% RSAPublicKey = #'RSAPublicKey'{publicExponent =
-%% Key#'RSAPrivateKey'.publicExponent,
-%% modulus = Key#'RSAPrivateKey'.modulus},
-
-encoded_tbs_cert(Cert) ->
- {ok, PKIXCert} =
- 'OTP-PUB-KEY':decode_TBSCert_exclusive(Cert),
- {'Certificate',
- {'Certificate_tbsCertificate', EncodedTBSCert}, _, _} = PKIXCert,
- EncodedTBSCert.
+ {ok, {_,_,[E]}} = public_key:pkix_path_validation(Trusted, [Cert1, Cert3,Cert4], [{verify,false}]),
+ % test_server:format("PV ~p ~n", [Result]),
+ ok.