mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
Support certificate revocation
This commit is contained in:
parent
61d1411ab3
commit
cc6f4b90fb
@ -12,9 +12,9 @@
|
||||
}).
|
||||
|
||||
-record(data_cert, {
|
||||
domain :: list(),
|
||||
pem :: jose_jwk:key(),
|
||||
path :: file:filename()
|
||||
domain :: bitstring(),
|
||||
pem :: bitstring(),
|
||||
path :: bitstring()
|
||||
}).
|
||||
|
||||
|
||||
|
@ -3,11 +3,13 @@
|
||||
-export([%% Ejabberdctl Commands
|
||||
get_certificates/2,
|
||||
list_certificates/1,
|
||||
revoke_certificate/2,
|
||||
%% Command Options Validity
|
||||
is_valid_account_opt/1,
|
||||
is_valid_verbose_opt/1,
|
||||
%% Misc
|
||||
generate_key/0,
|
||||
to_public/1,
|
||||
%% Debugging Scenarios
|
||||
scenario/3,
|
||||
scenario0/2,
|
||||
@ -46,6 +48,48 @@ is_valid_verbose_opt("plain") -> true;
|
||||
is_valid_verbose_opt("verbose") -> true;
|
||||
is_valid_verbose_opt(_) -> false.
|
||||
|
||||
%%
|
||||
%% Revoke Certificate
|
||||
%%
|
||||
|
||||
%% Add a try-catch to this stub
|
||||
revoke_certificate(CAUrl, Domain) ->
|
||||
revoke_certificate0(CAUrl, Domain).
|
||||
|
||||
revoke_certificate0(CAUrl, Domain) ->
|
||||
BinDomain = list_to_bitstring(Domain),
|
||||
case domain_certificate_exists(BinDomain) of
|
||||
{BinDomain, Certificate} ->
|
||||
?INFO_MSG("Certificate: ~p found!!", [Certificate]),
|
||||
ok = revoke_certificate1(CAUrl, Certificate),
|
||||
{ok, deleted};
|
||||
false ->
|
||||
{error, not_found}
|
||||
end.
|
||||
|
||||
revoke_certificate1(CAUrl, Cert = #data_cert{pem=PemEncodedCert}) ->
|
||||
{ok, _AccId, PrivateKey} = ensure_account_exists(),
|
||||
|
||||
Certificate = prepare_certificate_revoke(PemEncodedCert),
|
||||
|
||||
{ok, Dirs, Nonce} = ejabberd_acme_comm:directory(CAUrl),
|
||||
|
||||
Req = [{<<"certificate">>, Certificate}],
|
||||
{ok, [], Nonce1} = ejabberd_acme_comm:revoke_cert(Dirs, PrivateKey, Req, Nonce),
|
||||
ok.
|
||||
|
||||
prepare_certificate_revoke(PemEncodedCert) ->
|
||||
PemList = public_key:pem_decode(PemEncodedCert),
|
||||
PemCertEnc = lists:keyfind('Certificate', 1, PemList),
|
||||
PemCert = public_key:pem_entry_decode(PemCertEnc),
|
||||
DerCert = public_key:der_encode('Certificate', PemCert),
|
||||
Base64Cert = base64url:encode(DerCert),
|
||||
Base64Cert.
|
||||
|
||||
domain_certificate_exists(Domain) ->
|
||||
{ok, Certs} = read_certificates_persistent(),
|
||||
lists:keyfind(Domain, 1, Certs).
|
||||
|
||||
%%
|
||||
%% List Certificates
|
||||
%%
|
||||
@ -58,7 +102,7 @@ list_certificates(Verbose) ->
|
||||
Throw;
|
||||
E:R ->
|
||||
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, erlang:get_stacktrace()]),
|
||||
{error, get_certificates}
|
||||
{error, list_certificates}
|
||||
end.
|
||||
|
||||
list_certificates0(Verbose) ->
|
||||
@ -321,7 +365,7 @@ ensure_account_exists() ->
|
||||
make_csr(Attributes) ->
|
||||
Key = generate_key(),
|
||||
{_, KeyKey} = jose_jwk:to_key(Key),
|
||||
KeyPub = jose_jwk:to_public(Key),
|
||||
KeyPub = to_public(Key),
|
||||
try
|
||||
SubPKInfoAlgo = subject_pk_info_algo(KeyPub),
|
||||
{ok, RawBinPubKey} = raw_binary_public_key(KeyPub),
|
||||
@ -420,7 +464,9 @@ attribute_parser_fun({AttrName, AttrVal}) ->
|
||||
try
|
||||
#'AttributeTypeAndValue'{
|
||||
type = attribute_oid(AttrName),
|
||||
%% TODO: Check if every attribute should be encoded as common name
|
||||
%% TODO: Check if every attribute should be encoded as
|
||||
%% common name. Actually it doesn't matter in
|
||||
%% practice. Only in theory in order to have cleaner code.
|
||||
value = public_key:der_encode('X520CommonName', {printableString, AttrVal})
|
||||
%% value = length_bitstring(list_to_bitstring(AttrVal))
|
||||
}
|
||||
@ -469,6 +515,22 @@ not_before_not_after() ->
|
||||
NotAfter = xmpp_util:encode_timestamp({MegS+1, Sec, MicS}),
|
||||
{NotBefore, NotAfter}.
|
||||
|
||||
to_public(PrivateKey) ->
|
||||
jose_jwk:to_public(PrivateKey).
|
||||
%% case jose_jwk:to_key(PrivateKey) of
|
||||
%% #'RSAPrivateKey'{modulus = Mod, publicExponent = Exp} ->
|
||||
%% Public = #'RSAPublicKey'{modulus = Mod, publicExponent = Exp},
|
||||
%% jose_jwk:from_key(Public);
|
||||
%% _ ->
|
||||
%% jose_jwk:to_public(PrivateKey)
|
||||
%% end.
|
||||
|
||||
%% to_public(#'RSAPrivateKey'{modulus = Mod, publicExponent = Exp}) ->
|
||||
%% #'RSAPublicKey'{modulus = Mod, publicExponent = Exp};
|
||||
%% to_public(PrivateKey) ->
|
||||
%% jose_jwk:to_public(PrivateKey).
|
||||
|
||||
|
||||
is_error({error, _}) -> true;
|
||||
is_error(_) -> false.
|
||||
|
||||
@ -812,7 +874,9 @@ new_user_scenario(CAUrl, HttpDir) ->
|
||||
generate_key() ->
|
||||
?INFO_MSG("Generate RSA key pair~n", []),
|
||||
Key = public_key:generate_key({rsa, 2048, 65537}),
|
||||
jose_jwk:from_key(Key).
|
||||
Key1 = Key#'RSAPrivateKey'{version = 'two-prime'},
|
||||
jose_jwk:from_key(Key1).
|
||||
%% jose_jwk:generate_key({rsa, 2048}).
|
||||
-else.
|
||||
generate_key() ->
|
||||
?INFO_MSG("Generate EC key pair~n", []),
|
||||
|
@ -47,6 +47,7 @@
|
||||
%% Acme
|
||||
get_certificate/1,
|
||||
list_certificates/1,
|
||||
revoke_certificate/1,
|
||||
%% Purge DB
|
||||
delete_expired_messages/0, delete_old_messages/1,
|
||||
%% Mnesia
|
||||
@ -258,6 +259,12 @@ get_commands_spec() ->
|
||||
args_desc = ["Whether to print the whole certificate or just some metadata. Possible values: plain | verbose"],
|
||||
args = [{option, string}],
|
||||
result = {certificates, {list,{certificate, string}}}},
|
||||
#ejabberd_commands{name = revoke_certificate, tags = [acme],
|
||||
desc = "Revokes the selected certificate",
|
||||
module = ?MODULE, function = revoke_certificate,
|
||||
args_desc = ["The domain of the certificate in question"],
|
||||
args = [{domain, string}],
|
||||
result = {res, restuple}},
|
||||
|
||||
#ejabberd_commands{name = import_piefxis, tags = [mnesia],
|
||||
desc = "Import users data from a PIEFXIS file (XEP-0227)",
|
||||
@ -580,6 +587,8 @@ list_certificates(Verbose) ->
|
||||
{invalid_option, String}
|
||||
end.
|
||||
|
||||
revoke_certificate(Domain) ->
|
||||
ejabberd_acme:revoke_certificate("http://localhost:4000", Domain).
|
||||
|
||||
%%%
|
||||
%%% Purge DB
|
||||
|
Loading…
Reference in New Issue
Block a user