From c20bfb3422be8b67479cc1a1e79fc8b1c7dc1d5d Mon Sep 17 00:00:00 2001 From: Konstantinos Kallas Date: Thu, 10 Aug 2017 17:23:13 +0300 Subject: [PATCH] Revoke Certificate: Jose Private Key Instead of signing the jose object with the account private key, it now signs the object using the certificate private key. This is useful in case the user wants to revoke a old certificate whose account key doesn't exist anymore. --- src/ejabberd_acme.erl | 45 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/src/ejabberd_acme.erl b/src/ejabberd_acme.erl index 4194f9393..459b7e3d0 100644 --- a/src/ejabberd_acme.erl +++ b/src/ejabberd_acme.erl @@ -474,7 +474,6 @@ 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 -> @@ -483,14 +482,12 @@ revoke_certificate0(CAUrl, Domain) -> -spec revoke_certificate1(url(), data_cert()) -> ok. revoke_certificate1(CAUrl, Cert = #data_cert{pem=PemEncodedCert}) -> - {ok, _AccId, PrivateKey} = ensure_account_exists(), - - Certificate = prepare_certificate_revoke(PemEncodedCert), + {Certificate, CertPrivateKey} = 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, [], Nonce1} = ejabberd_acme_comm:revoke_cert(Dirs, CertPrivateKey, Req, Nonce), ok = remove_certificate_persistent(Cert), ok. @@ -501,7 +498,9 @@ prepare_certificate_revoke(PemEncodedCert) -> PemCert = public_key:pem_entry_decode(PemCertEnc), DerCert = public_key:der_encode('Certificate', PemCert), Base64Cert = base64url:encode(DerCert), - Base64Cert. + + Key = find_private_key_in_pem(PemEncodedCert), + {Base64Cert, Key}. -spec domain_certificate_exists(bitstring()) -> {bitstring(), data_cert()} | false. domain_certificate_exists(Domain) -> @@ -719,9 +718,43 @@ utc_string_to_datetime(UtcString) -> throw({error, utc_string_to_datetime}) end. +-spec find_private_key_in_pem(pem()) -> {ok, jose_jwk:key()} | false. +find_private_key_in_pem(Pem) -> + PemList = public_key:pem_decode(Pem), + case find_private_key_in_pem1(private_key_types(), PemList) of + false -> + false; + PemKey -> + Key = public_key:pem_entry_decode(PemKey), + JoseKey = jose_jwk:from_key(Key), + JoseKey + end. + + +-spec find_private_key_in_pem1([public_key:pki_asn1_type()], + [public_key:pem_entry()]) -> + public_key:pem_entry() | false. +find_private_key_in_pem1([], _PemList) -> + false; +find_private_key_in_pem1([Type|Types], PemList) -> + case lists:keyfind(Type, 1, PemList) of + false -> + find_private_key_in_pem1(Types, PemList); + Key -> + Key + end. + + +-spec parse_domain_string(string()) -> [string()]. parse_domain_string(DomainString) -> string:tokens(DomainString, ";"). +-spec private_key_types() -> [public_key:pki_asn1_type()]. +private_key_types() -> + ['RSAPrivateKey', + 'DSAPrivateKey', + 'ECPrivateKey']. + -spec is_error(_) -> boolean(). is_error({error, _}) -> true; is_error({error, _, _}) -> true;