aboutsummaryrefslogtreecommitdiffstats
path: root/lib/public_key
diff options
context:
space:
mode:
Diffstat (limited to 'lib/public_key')
-rw-r--r--lib/public_key/doc/src/public_key.xml86
-rw-r--r--lib/public_key/src/pubkey_cert.erl253
-rw-r--r--lib/public_key/src/public_key.erl25
-rw-r--r--lib/public_key/test/public_key_SUITE.erl100
4 files changed, 457 insertions, 7 deletions
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 942203bd12..5a4fdf057b 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -119,6 +119,10 @@
<tag><c>ec_private_key() =</c></tag>
<item><p><c>#'ECPrivateKey'{}</c></p></item>
+ <tag><c>key_params() =</c></tag>
+ <item><p> #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{}
+ | {rsa, Size::integer(), PubExp::integer()} </p></item>
+
<tag><c>public_crypt_options() =</c></tag>
<item><p><c>[{rsa_pad, rsa_padding()}]</c></p></item>
@@ -347,8 +351,7 @@
<name>generate_key(Params) -> {Public::binary(), Private::binary()} | #'ECPrivateKey'{} | #'RSAPrivateKey'{}</name>
<fsummary>Generates a new keypair.</fsummary>
<type>
- <v>Params = #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{}
- | {rsa, Size::integer(), PubExp::integer} </v>
+ <v>Params = key_params()</v>
</type>
<desc>
<p>Generates a new keypair. Note that except for Diffie-Hellman
@@ -769,6 +772,85 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</desc>
</func>
+ <func>
+ <name>pkix_test_data(Options) -> Config </name>
+ <fsummary>Creates certificate test data.</fsummary>
+ <type>
+ <v>Options = #{chain_type() := chain_opts()} </v>
+ <d>Options for ROOT, Intermediate and Peer certs</d>
+
+ <v>chain_type() = server_chain | client_chain </v>
+
+ <v>chain_opts() = #{chain_end() := [cert_opt()],
+ intermediates => [[cert_opt()]]}</v>
+ <d>A valid chain must have at least a ROOT and a peer cert</d>
+
+ <v>chain_end() = root | peer </v>
+
+ <v>cert_opt() = {Key, Value}</v>
+ <d>For available options see <seealso marker="#cert_opt"> cert_opt()</seealso> below.</d>
+
+ <v>Config = #{server_config := [conf_opt()],
+ client_config := [conf_opt()]}</v>
+
+ <v>conf_opt() = {cert, der_encoded()} | {key, der_encoded()} |{cacerts, [der_encoded()]}</v>
+ <d>This is a subset of the type <seealso marker="ssl#type-ssloption"> ssl:ssl_option()</seealso> </d>
+ </type>
+
+ <desc>
+ <p>Creates certificate test data to facilitate automated testing
+ of applications using X509-certificates often through
+ SSL/TLS. The test data can be used when you have control
+ over both the client and the server in a test scenario.
+ </p>
+
+ <p> The <marker id="cert_opt"/> cert_opt() type consists of the following options: </p>
+ <taglist>
+ <tag> {digest, digest_type()}</tag>
+ <item><p>Hash algorithm to be used for
+ signing the certificate together with the key option. Defaults to sha that is sha1.
+ </p></item>
+ <tag> {key, key_params() | private_key()}</tag>
+ <item><p>Parameters to be used to call public_key:generate_key/1, to generate a key, or an existing
+ key. Defaults to generating an ECDSA key. Note this could fail if Erlang/OTP is compiled with a very old
+ cryptolib.</p></item>
+ <tag> {validity, {From::erlang:timestamp(), To::erlang:timestamp()}} </tag>
+ <item><p>The validity period of the certificate.</p></item>
+ <tag> {extensions, [#'Extension'{}]}</tag>
+ <item><p> Extensions to include in the certificate.</p>
+
+ <p>Default extensions included in CA certificates if not
+ otherwise specified are: </p>
+ <code>[#'Extension'{extnID = ?'id-ce-keyUsage',
+ extnValue = [keyCertSign, cRLSign],
+ critical = false},
+#'Extension'{extnID = ?'id-ce-basicConstraints',
+ extnValue = #'BasicConstraints'{cA = true},
+ critical = true}]
+ </code>
+
+ <p>Default extensions included in the server peer cert if not
+ otherwise specified are: </p>
+ <code>[#'Extension'{extnID = ?'id-ce-keyUsage',
+ extnValue = [digitalSignature, keyAgreement],
+ critical = false},
+#'Extension'{extnID = ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, Hostname}],
+ critical = false}]
+ </code>
+ <p>Hostname is the result of calling net_adm:localhost() in the Erlang node
+ where this funcion is called.
+ </p></item>
+
+ </taglist>
+
+ <note><p>
+ Note that the generated certificates and keys does not provide a formally correct PKIX-trust-chain
+ and they can not be used to achieve real security. This function is provided for testing purposes only.
+</p></note>
+ </desc>
+ </func>
+
<func>
<name>pkix_verify(Cert, Key) -> boolean()</name>
<fsummary>Verifies PKIX x.509 certificate signature.</fsummary>
diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl
index f45f2c2e9a..13833830a7 100644
--- a/lib/public_key/src/pubkey_cert.erl
+++ b/lib/public_key/src/pubkey_cert.erl
@@ -32,12 +32,25 @@
is_issuer/2, issuer_id/2, distribution_points/1,
is_fixed_dh_cert/1, verify_data/1, verify_fun/4,
select_extension/2, match_name/3,
- extensions_list/1, cert_auth_key_id/1, time_str_2_gregorian_sec/1]).
+ extensions_list/1, cert_auth_key_id/1, time_str_2_gregorian_sec/1,
+ gen_test_certs/1]).
-define(NULL, 0).
-
+
+-export_type([chain_opts/0, test_config/0]).
+
+-type cert_opt() :: {digest, public_key:digest_type()} |
+ {key, public_key:key_params() | public_key:private_key()} |
+ {validity, {From::erlang:timestamp(), To::erlang:timestamp()}} |
+ {extensions, [#'Extension'{}]}.
+-type chain_end() :: root | peer.
+-type chain_opts() :: #{chain_end() := [cert_opt()], intermediates => [[cert_opt()]]}.
+-type conf_opt() :: {cert, public_key:der_encoded()} |
+ {key, public_key:der_encoded()} |
+ {cacerts, [public_key:der_encoded()]}.
+-type test_config() :: #{server_config := [conf_opt()], client_config := [conf_opt()]}.
%%====================================================================
-%% Internal application API
+%% Internal application APIu
%%====================================================================
%%--------------------------------------------------------------------
@@ -417,6 +430,31 @@ match_name(Fun, Name, PermittedName, [Head | Tail]) ->
false ->
match_name(Fun, Name, Head, Tail)
end.
+%%%
+-spec gen_test_certs(#{server_chain:= chain_opts(), client_chain:= chain_opts()}) -> test_config().
+
+%% Generates server and and client configuration for testing
+%% purposes. All certificate options have default values
+gen_test_certs(#{client_chain := #{root := ClientRootConf,
+ intermediates := ClientCAs,
+ peer := ClientPeer},
+ server_chain :=
+ #{root := ServerRootConf,
+ intermediates := ServerCAs,
+ peer := ServerPeer}}) ->
+ SRootKey = gen_key(proplists:get_value(key, ServerRootConf, default_key_gen())),
+ CRootKey = gen_key(proplists:get_value(key, ClientRootConf, default_key_gen())),
+ ServerRoot = root_cert("server", SRootKey, ClientRootConf),
+ ClientRoot = root_cert("client", CRootKey, ServerRootConf),
+
+ [{ServerDERCert, ServerDERKey} | ServerCAsKeys] = config(server, ServerRoot,
+ SRootKey, lists:reverse([ServerPeer | lists:reverse(ServerCAs)])),
+ [{ClientDERCert, ClientDERKey} | ClientCAsKeys] = config(client, ClientRoot,
+ CRootKey, lists:reverse([ClientPeer | lists:reverse(ClientCAs)])),
+ ServerDERCA = ca_config(ClientRoot, ServerCAsKeys),
+ ClientDERCA = ca_config(ServerRoot, ClientCAsKeys),
+ #{server_config => [{cert, ServerDERCert}, {key, ServerDERKey}, {cacerts, ServerDERCA}],
+ client_config => [{cert, ClientDERCert}, {key, ClientDERKey}, {cacerts, ClientDERCA}]}.
%%--------------------------------------------------------------------
%%% Internal functions
@@ -1064,3 +1102,212 @@ missing_basic_constraints(OtpCert, SelfSigned, ValidationState, VerifyFun, UserS
Len - 1},
UserState}
end.
+
+ gen_key(KeyGen) ->
+ case is_key(KeyGen) of
+ true ->
+ KeyGen;
+ false ->
+ public_key:generate_key(KeyGen)
+ end.
+
+is_key(#'DSAPrivateKey'{}) ->
+ true;
+is_key(#'RSAPrivateKey'{}) ->
+ true;
+is_key(#'ECPrivateKey'{}) ->
+ true;
+is_key(_) ->
+ false.
+
+root_cert(Role, PrivKey, Opts) ->
+ TBS = cert_template(),
+ Issuer = issuer("root", Role, " ROOT CA"),
+ OTPTBS = TBS#'OTPTBSCertificate'{
+ signature = sign_algorithm(PrivKey, Opts),
+ issuer = Issuer,
+ validity = validity(Opts),
+ subject = Issuer,
+ subjectPublicKeyInfo = public_key(PrivKey),
+ extensions = extensions(Role, ca, Opts)
+ },
+ public_key:pkix_sign(OTPTBS, PrivKey).
+
+cert_template() ->
+ #'OTPTBSCertificate'{
+ version = v3,
+ serialNumber = trunc(rand:uniform()*100000000)*10000 + 1,
+ issuerUniqueID = asn1_NOVALUE,
+ subjectUniqueID = asn1_NOVALUE
+ }.
+issuer(Contact, Role, Name) ->
+ subject(Contact, Role ++ Name).
+
+subject(Contact, Name) ->
+ Opts = [{email, Contact ++ "@erlang.org"},
+ {name, Name},
+ {city, "Stockholm"},
+ {country, "SE"},
+ {org, "erlang"},
+ {org_unit, "automated testing"}],
+ 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]}.
+
+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({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}.
+
+validity(Opts) ->
+ DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
+ 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 = rsa_digest_oid(proplists:get_value(digest, Opts, sha1)),
+ #'SignatureAlgorithm'{algorithm = Type,
+ parameters = 'NULL'};
+sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) ->
+ #'SignatureAlgorithm'{algorithm = ?'id-dsa-with-sha1',
+ parameters = {params,#'Dss-Parms'{p=P, q=Q, g=G}}};
+sign_algorithm(#'ECPrivateKey'{parameters = Parms}, Opts) ->
+ Type = ecdsa_digest_oid(proplists:get_value(digest, Opts, sha1)),
+ #'SignatureAlgorithm'{algorithm = Type,
+ parameters = Parms}.
+rsa_digest_oid(sha1) ->
+ ?'sha1WithRSAEncryption';
+rsa_digest_oid(sha512) ->
+ ?'sha512WithRSAEncryption';
+rsa_digest_oid(sha384) ->
+ ?'sha384WithRSAEncryption';
+rsa_digest_oid(sha256) ->
+ ?'sha256WithRSAEncryption';
+rsa_digest_oid(md5) ->
+ ?'md5WithRSAEncryption'.
+
+ecdsa_digest_oid(sha1) ->
+ ?'ecdsa-with-SHA1';
+ecdsa_digest_oid(sha512) ->
+ ?'ecdsa-with-SHA512';
+ecdsa_digest_oid(sha384) ->
+ ?'ecdsa-with-SHA384';
+ecdsa_digest_oid(sha256) ->
+ ?'ecdsa-with-SHA256'.
+
+config(Role, Root, Key, Opts) ->
+ cert_chain(Role, Root, Key, Opts).
+
+cert_chain(Role, Root, RootKey, Opts) ->
+ cert_chain(Role, Root, RootKey, Opts, 0, []).
+
+cert_chain(Role, IssuerCert, IssuerKey, [PeerOpts], _, Acc) ->
+ Key = gen_key(proplists:get_value(key, PeerOpts, default_key_gen())),
+ Cert = cert(Role, public_key:pkix_decode_cert(IssuerCert, otp),
+ IssuerKey, Key, "admin", " Peer cert", PeerOpts, peer),
+ [{Cert, Key}, {IssuerCert, IssuerKey} | Acc];
+cert_chain(Role, IssuerCert, IssuerKey, [CAOpts | Rest], N, Acc) ->
+ Key = gen_key(proplists:get_value(key, CAOpts, default_key_gen())),
+ Cert = cert(Role, public_key:pkix_decode_cert(IssuerCert, otp), IssuerKey, Key, "webadmin",
+ " Intermidiate CA " ++ integer_to_list(N), CAOpts, ca),
+ cert_chain(Role, Cert, Key, Rest, N+1, [{IssuerCert, IssuerKey} | Acc]).
+
+cert(Role, #'OTPCertificate'{tbsCertificate = #'OTPTBSCertificate'{subject = Issuer}},
+ PrivKey, Key, Contact, Name, Opts, Type) ->
+ TBS = cert_template(),
+ OTPTBS = TBS#'OTPTBSCertificate'{
+ signature = sign_algorithm(PrivKey, Opts),
+ issuer = Issuer,
+ validity = validity(Opts),
+ subject = subject(Contact, atom_to_list(Role) ++ Name),
+ subjectPublicKeyInfo = public_key(Key),
+ extensions = extensions(Role, Type, Opts)
+
+ },
+ public_key:pkix_sign(OTPTBS, PrivKey).
+
+ca_config(Root, CAsKeys) ->
+ [Root | [CA || {CA, _} <- CAsKeys]].
+
+default_key_gen() ->
+ case crypto:ec_curves() of
+ [] ->
+ {rsa, 2048, 17};
+ [Curve |_] ->
+ Oid = pubkey_cert_records:namedCurves(Curve),
+ {namedCurve, Oid}
+ end.
+
+public_key(#'RSAPrivateKey'{modulus=N, publicExponent=E}) ->
+ Public = #'RSAPublicKey'{modulus=N, publicExponent=E},
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?rsaEncryption, parameters='NULL'},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
+ subjectPublicKey = Public};
+public_key(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa',
+ parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y};
+public_key(#'ECPrivateKey'{version = _Version,
+ privateKey = _PrivKey,
+ parameters = Params,
+ publicKey = PubKey}) ->
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-ecPublicKey', parameters=Params},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
+ subjectPublicKey = #'ECPoint'{point = PubKey}}.
+
+extensions(Role, Type, Opts) ->
+ Exts = proplists:get_value(extensions, Opts, []),
+ add_default_extensions(Role, Type, Exts).
+
+add_default_extensions(_, ca, Exts) ->
+ Default = [#'Extension'{extnID = ?'id-ce-keyUsage',
+ extnValue = [keyCertSign, cRLSign],
+ critical = false},
+ #'Extension'{extnID = ?'id-ce-basicConstraints',
+ extnValue = #'BasicConstraints'{cA = true},
+ critical = true}],
+ add_default_extensions(Default, Exts);
+
+add_default_extensions(server, peer, Exts) ->
+ Hostname = net_adm:localhost(),
+ Default = [#'Extension'{extnID = ?'id-ce-keyUsage',
+ extnValue = [digitalSignature, keyAgreement],
+ critical = false},
+ #'Extension'{extnID = ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, Hostname}],
+ critical = false}
+ ],
+ add_default_extensions(Default, Exts);
+
+add_default_extensions(_, peer, Exts) ->
+ Exts.
+
+add_default_extensions(Defaults0, Exts) ->
+ Defaults = lists:filtermap(fun(#'Extension'{extnID = ID} = Ext) ->
+ case lists:keymember(ID, 2, Exts) of
+ true ->
+ false;
+ false ->
+ {true, Ext}
+ end
+ end, Defaults0),
+ Exts ++ Defaults.
+
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 9a61184f8a..cc01b61433 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -58,11 +58,13 @@
pkix_match_dist_point/2,
pkix_crl_verify/2,
pkix_crl_issuer/1,
- short_name_hash/1
+ short_name_hash/1,
+ pkix_test_data/1
]).
-export_type([public_key/0, private_key/0, pem_entry/0,
- pki_asn1_type/0, asn1_type/0, ssh_file/0, der_encoded/0]).
+ pki_asn1_type/0, asn1_type/0, ssh_file/0, der_encoded/0,
+ key_params/0, digest_type/0]).
-type public_key() :: rsa_public_key() | dsa_public_key() | ec_public_key().
-type private_key() :: rsa_private_key() | dsa_private_key() | ec_private_key().
@@ -75,6 +77,8 @@
-type ecpk_parameters_api() :: ecpk_parameters() | #'ECParameters'{} | {namedCurve, Name::atom()}.
-type ec_public_key() :: {#'ECPoint'{}, ecpk_parameters_api()}.
-type ec_private_key() :: #'ECPrivateKey'{}.
+-type key_params() :: #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{} |
+ {rsa, Size::integer(), PubExp::integer()}.
-type der_encoded() :: binary().
-type pki_asn1_type() :: 'Certificate' | 'RSAPrivateKey' | 'RSAPublicKey'
| 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter'
@@ -102,6 +106,7 @@
-type crl_reason() :: unspecified | keyCompromise | cACompromise | affiliationChanged | superseded
| cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise.
-type oid() :: tuple().
+-type chain_type() :: server_chain | client_chain.
-define(UINT32(X), X:32/unsigned-big-integer).
-define(DER_NULL, <<5, 0>>).
@@ -1027,6 +1032,22 @@ short_name_hash({rdnSequence, _Attributes} = Name) ->
<<HashValue:32/little, _/binary>> = crypto:hash(sha, HashThis),
string:to_lower(string:right(integer_to_list(HashValue, 16), 8, $0)).
+
+%%--------------------------------------------------------------------
+-spec pkix_test_data(#{chain_type() := pubkey_cert:chain_opts()}) ->
+ pubkey_cert:test_config().
+
+%% Description: Generates OpenSSL-style hash of a name.
+%%--------------------------------------------------------------------
+
+pkix_test_data(#{client_chain := ClientChain0,
+ server_chain := ServerChain0}) ->
+ Default = #{intermediates => []},
+ ClientChain = maps:merge(Default, ClientChain0),
+ ServerChain = maps:merge(Default, ServerChain0),
+ pubkey_cert:gen_test_certs(#{client_chain => ClientChain,
+ server_chain => ServerChain}).
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 4b1b771613..374fb20375 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -48,6 +48,8 @@ all() ->
pkix_verify_hostname_cn,
pkix_verify_hostname_subjAltName,
pkix_verify_hostname_options,
+ pkix_test_data_all_default,
+ pkix_test_data,
short_cert_issuer_hash, short_crl_issuer_hash,
ssh_hostkey_fingerprint_md5_implicit,
ssh_hostkey_fingerprint_md5,
@@ -93,6 +95,14 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
%%-------------------------------------------------------------------
+
+init_per_testcase(pkix_test_data_all_default, Config) ->
+ case crypto:ec_curves() of
+ [] ->
+ {skip, missing_ecc_support};
+ _ ->
+ init_common_per_testcase(Config)
+ end;
init_per_testcase(TestCase, Config) ->
case TestCase of
ssh_hostkey_fingerprint_md5_implicit -> init_fingerprint_testcase([md5], Config);
@@ -1047,6 +1057,84 @@ general_name(Config) when is_list(Config) ->
authorityCertSerialNumber =
1}).
%%--------------------------------------------------------------------
+
+pkix_test_data_all_default() ->
+ [{doc, "Test API function pkix_test_data/1"}].
+
+pkix_test_data_all_default(Config) when is_list(Config) ->
+ #{server_config := ServerConf0,
+ client_config := ClientConf0} = public_key:pkix_test_data(#{server_chain =>
+ #{root => [],
+ intermediates => [[]],
+ peer => []},
+ client_chain =>
+ #{root => [],
+ intermediates => [[]],
+ peer => []}}),
+ check_conf_member(ServerConf0, [key, cert, cacerts]),
+ check_conf_member(ClientConf0, [key, cert, cacerts]),
+
+ 3 = length(proplists:get_value(cacerts, ServerConf0)),
+ 3 = length(proplists:get_value(cacerts, ServerConf0)),
+
+ #{server_config := ServerConf1,
+ client_config := ClientConf1} = public_key:pkix_test_data(#{server_chain =>
+ #{root => [],
+ peer => []},
+ client_chain =>
+ #{root => [],
+ peer => []}}),
+ 2 = length(proplists:get_value(cacerts, ServerConf1)),
+ 2 = length(proplists:get_value(cacerts, ServerConf1)),
+
+ check_conf_member(ServerConf1, [key, cert, cacerts]),
+ check_conf_member(ClientConf1, [key, cert, cacerts]).
+
+
+pkix_test_data() ->
+ [{doc, "Test API function pkix_test_data/1"}].
+
+pkix_test_data(Config) when is_list(Config) ->
+ {Year, Month, Day} = date(),
+ Keygen =
+ case crypto:ec_curves() of
+ [] ->
+ {rsa, 2048, 17};
+ [Curve |_] ->
+ Oid = pubkey_cert_records:namedCurves(Curve),
+ {namedCurve, Oid}
+ end,
+ #{server_config := ServerConf0,
+ client_config := ClientConf0} =
+ public_key:pkix_test_data(#{server_chain =>
+ #{root => [],
+ intermediates => [],
+ peer => [{key, hardcode_rsa_key()}]},
+ client_chain =>
+ #{root => [{validity, {{Year-2, Month, Day},
+ {Year-1, Month, Day}}}],
+ intermediates =>
+ [[{extensions, [#'Extension'{extnID = ?'id-ce-basicConstraints',
+ extnValue = #'BasicConstraints'{cA=true,
+ pathLenConstraint = 1},
+ critical = true}]}]],
+ peer => [{key, Keygen}, {digest, sha1}]}}),
+ check_conf_member(ServerConf0, [key, cert, cacerts]),
+ check_conf_member(ClientConf0, [key, cert, cacerts]).
+
+
+
+check_conf_member(_, []) ->
+ true;
+check_conf_member(Conf, [Member | Rest]) ->
+ case lists:keymember(Member, 1, Conf) of
+ true ->
+ check_conf_member(Conf, Rest);
+ false ->
+ ct:fail({misssing_conf, Member})
+ end.
+
+%%--------------------------------------------------------------------
short_cert_issuer_hash() ->
[{doc, "Test OpenSSL-style hash for certificate issuer"}].
@@ -1168,3 +1256,15 @@ ssh_hostkey(rsa) ->
public_key),
PKdecoded.
+hardcode_rsa_key() ->
+ #'RSAPrivateKey'{
+ version = 'two-prime',
+ modulus = 23995666614853919027835084074500048897452890537492185072956789802729257783422306095699263934587064480357348855732149402060270996295002843755712064937715826848741191927820899197493902093529581182351132392364214171173881547273475904587683433713767834856230531387991145055273426806331200574039205571401702219159773947658558490957010003143162250693492642996408861265758000254664396313741422909188635443907373976005987612936763564996605457102336549804831742940035613780926178523017685712710473543251580072875247250504243621640157403744718833162626193206685233710319205099867303242759099560438381385658382486042995679707669,
+ publicExponent = 17,
+ privateExponent = 11292078406990079542510627799764728892919007311761028269626724613049062486316379339152594792746853873109340637991599718616598115903530750002688030558925094987642913848386305504703012749896273497577003478759630198199473669305165131570674557041773098755873191241407597673069847908861741446606684974777271632545629600685952292605647052193819136445675100211504432575554351515262198132231537860917084269870590492135731720141577986787033006338680118008484613510063003323516659048210893001173583018220214626635609151105287049126443102976056146630518124476470236027123782297108342869049542023328584384300970694412006494684657,
+ prime1 = 169371138592582642967021557955633494538845517070305333860805485424261447791289944610138334410987654265476540480228705481960508520379619587635662291973699651583489223555422528867090299996446070521801757353675026048850480903160224210802452555900007597342687137394192939372218903554801584969667104937092080815197,
+ prime2 = 141675062317286527042995673340952251894209529891636708844197799307963834958115010129693036021381525952081167155681637592199810112261679449166276939178032066869788822014115556349519329537177920752776047051833616197615329017439297361972726138285974555338480581117881706656603857310337984049152655480389797687577,
+ exponent1 = 119556097830058336212015217380447172615655659108450823901745048534772786676204666783627059584226579481512852103690850928442711896738555003036938088452023283470698275450886490965004917644550167427154181661417665446247398284583687678213495921811770068712485038160606780733330990744565824684470897602653233516609,
+ exponent2 = 41669135975672507953822256864985956439473391144599032012999352737636422046504414744027363535700448809435637398729893409470532385959317485048904982111185902020526124121798693043976273393287623750816484427009887116945685005129205106462566511260580751570141347387612266663707016855981760014456663376585234613993,
+ coefficient = 76837684977089699359024365285678488693966186052769523357232308621548155587515525857011429902602352279058920284048929101483304120686557782043616693940283344235057989514310975192908256494992960578961614059245280827077951132083993754797053182279229469590276271658395444955906108899267024101096069475145863928441,
+ otherPrimeInfos = asn1_NOVALUE}.