mirror of
https://github.com/processone/ejabberd.git
synced 2024-06-02 21:17:12 +02:00
Acquire certificates for all subdomains of a host and include them in SAN
This commit is contained in:
parent
37a54cd498
commit
25ca6e5582
|
@ -156,8 +156,12 @@ format_get_certificate({error, Domain, Reason}) ->
|
||||||
{'error', bitstring(), _}.
|
{'error', bitstring(), _}.
|
||||||
get_certificate(CAUrl, DomainName, PrivateKey) ->
|
get_certificate(CAUrl, DomainName, PrivateKey) ->
|
||||||
try
|
try
|
||||||
{ok, _Authz} = create_new_authorization(CAUrl, DomainName, PrivateKey),
|
AllSubDomains = find_all_sub_domains(DomainName),
|
||||||
create_new_certificate(CAUrl, DomainName, PrivateKey)
|
lists:foreach(
|
||||||
|
fun(Domain) ->
|
||||||
|
{ok, _Authz} = create_new_authorization(CAUrl, Domain, PrivateKey)
|
||||||
|
end, [DomainName|AllSubDomains]),
|
||||||
|
create_new_certificate(CAUrl, {DomainName, AllSubDomains}, PrivateKey)
|
||||||
catch
|
catch
|
||||||
throw:Throw ->
|
throw:Throw ->
|
||||||
Throw;
|
Throw;
|
||||||
|
@ -235,13 +239,14 @@ create_new_authorization(CAUrl, DomainName, PrivateKey) ->
|
||||||
throw({error, DomainName, authorization})
|
throw({error, DomainName, authorization})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec create_new_certificate(url(), bitstring(), jose_jwk:key()) ->
|
-spec create_new_certificate(url(), {bitstring(), [bitstring()]}, jose_jwk:key()) ->
|
||||||
{ok, bitstring(), pem()}.
|
{ok, bitstring(), pem()}.
|
||||||
create_new_certificate(CAUrl, DomainName, PrivateKey) ->
|
create_new_certificate(CAUrl, {DomainName, AllSubDomains}, PrivateKey) ->
|
||||||
try
|
try
|
||||||
{ok, Dirs, Nonce0} = ejabberd_acme_comm:directory(CAUrl),
|
{ok, Dirs, Nonce0} = ejabberd_acme_comm:directory(CAUrl),
|
||||||
CSRSubject = [{commonName, bitstring_to_list(DomainName)}],
|
CSRSubject = [{commonName, bitstring_to_list(DomainName)}],
|
||||||
{CSR, CSRKey} = make_csr(CSRSubject),
|
SANs = [{dNSName, SAN} || SAN <- AllSubDomains],
|
||||||
|
{CSR, CSRKey} = make_csr(CSRSubject, SANs),
|
||||||
{NotBefore, NotAfter} = not_before_not_after(),
|
{NotBefore, NotAfter} = not_before_not_after(),
|
||||||
Req =
|
Req =
|
||||||
[{<<"csr">>, CSR},
|
[{<<"csr">>, CSR},
|
||||||
|
@ -572,8 +577,9 @@ certificate_exists(Host) ->
|
||||||
%% For now we accept only generating a key of
|
%% For now we accept only generating a key of
|
||||||
%% specific type for signing the csr
|
%% specific type for signing the csr
|
||||||
|
|
||||||
-spec make_csr(proplist()) -> {binary(), jose_jwk:key()}.
|
-spec make_csr(proplist(), [{dNSName, bitstring()}])
|
||||||
make_csr(Attributes) ->
|
-> {binary(), jose_jwk:key()}.
|
||||||
|
make_csr(Attributes, SANs) ->
|
||||||
Key = generate_key(),
|
Key = generate_key(),
|
||||||
{_, KeyKey} = jose_jwk:to_key(Key),
|
{_, KeyKey} = jose_jwk:to_key(Key),
|
||||||
KeyPub = to_public(Key),
|
KeyPub = to_public(Key),
|
||||||
|
@ -582,7 +588,8 @@ make_csr(Attributes) ->
|
||||||
{ok, RawBinPubKey} = raw_binary_public_key(KeyPub),
|
{ok, RawBinPubKey} = raw_binary_public_key(KeyPub),
|
||||||
SubPKInfo = subject_pk_info(SubPKInfoAlgo, RawBinPubKey),
|
SubPKInfo = subject_pk_info(SubPKInfoAlgo, RawBinPubKey),
|
||||||
{ok, Subject} = attributes_from_list(Attributes),
|
{ok, Subject} = attributes_from_list(Attributes),
|
||||||
CRI = certificate_request_info(SubPKInfo, Subject),
|
ExtensionRequest = extension_request(SANs),
|
||||||
|
CRI = certificate_request_info(SubPKInfo, Subject, ExtensionRequest),
|
||||||
{ok, EncodedCRI} = der_encode(
|
{ok, EncodedCRI} = der_encode(
|
||||||
'CertificationRequestInfo',
|
'CertificationRequestInfo',
|
||||||
CRI),
|
CRI),
|
||||||
|
@ -617,12 +624,27 @@ subject_pk_info(Algo, RawBinPubKey) ->
|
||||||
subjectPublicKey = RawBinPubKey
|
subjectPublicKey = RawBinPubKey
|
||||||
}.
|
}.
|
||||||
|
|
||||||
certificate_request_info(SubPKInfo, Subject) ->
|
extension(SANs) ->
|
||||||
|
#'Extension'{
|
||||||
|
extnID = attribute_oid(subjectAltName),
|
||||||
|
critical = false,
|
||||||
|
extnValue = public_key:der_encode('SubjectAltName', SANs)}.
|
||||||
|
|
||||||
|
extension_request(SANs) ->
|
||||||
|
#'AttributePKCS-10'{
|
||||||
|
type = ?'pkcs-9-at-extensionRequest',
|
||||||
|
values = [{'asn1_OPENTYPE',
|
||||||
|
public_key:der_encode(
|
||||||
|
'ExtensionRequest',
|
||||||
|
[extension(SANs)])}]
|
||||||
|
}.
|
||||||
|
|
||||||
|
certificate_request_info(SubPKInfo, Subject, ExtensionRequest) ->
|
||||||
#'CertificationRequestInfo'{
|
#'CertificationRequestInfo'{
|
||||||
version = 0,
|
version = 0,
|
||||||
subject = Subject,
|
subject = Subject,
|
||||||
subjectPKInfo = SubPKInfo,
|
subjectPKInfo = SubPKInfo,
|
||||||
attributes = []
|
attributes = [ExtensionRequest]
|
||||||
}.
|
}.
|
||||||
|
|
||||||
signature_algo(_Key, _Hash) ->
|
signature_algo(_Key, _Hash) ->
|
||||||
|
@ -693,6 +715,7 @@ attribute_oid(countryName) -> ?'id-at-countryName';
|
||||||
attribute_oid(stateOrProvinceName) -> ?'id-at-stateOrProvinceName';
|
attribute_oid(stateOrProvinceName) -> ?'id-at-stateOrProvinceName';
|
||||||
attribute_oid(localityName) -> ?'id-at-localityName';
|
attribute_oid(localityName) -> ?'id-at-localityName';
|
||||||
attribute_oid(organizationName) -> ?'id-at-organizationName';
|
attribute_oid(organizationName) -> ?'id-at-organizationName';
|
||||||
|
attribute_oid(subjectAltName) -> ?'id-ce-subjectAltName';
|
||||||
attribute_oid(_) -> error(bad_attributes).
|
attribute_oid(_) -> error(bad_attributes).
|
||||||
|
|
||||||
|
|
||||||
|
@ -793,6 +816,15 @@ private_key_types() ->
|
||||||
'DSAPrivateKey',
|
'DSAPrivateKey',
|
||||||
'ECPrivateKey'].
|
'ECPrivateKey'].
|
||||||
|
|
||||||
|
-spec find_all_sub_domains(bitstring()) -> [bitstring()].
|
||||||
|
find_all_sub_domains(DomainName) ->
|
||||||
|
AllRoutes = ejabberd_router:get_all_routes(),
|
||||||
|
DomainLen = size(DomainName),
|
||||||
|
[Route || Route <- AllRoutes,
|
||||||
|
binary:longest_common_suffix([DomainName, Route])
|
||||||
|
=:= DomainLen].
|
||||||
|
|
||||||
|
|
||||||
-spec is_error(_) -> boolean().
|
-spec is_error(_) -> boolean().
|
||||||
is_error({error, _}) -> true;
|
is_error({error, _}) -> true;
|
||||||
is_error({error, _, _}) -> true;
|
is_error({error, _, _}) -> true;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user