acme.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2019 New Vector Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import logging
  16. import twisted
  17. import twisted.internet.error
  18. from twisted.web import server, static
  19. from twisted.web.resource import Resource
  20. from synapse.app import check_bind_error
  21. logger = logging.getLogger(__name__)
  22. ACME_REGISTER_FAIL_ERROR = """
  23. --------------------------------------------------------------------------------
  24. Failed to register with the ACME provider. This is likely happening because the installation
  25. is new, and ACME v1 has been deprecated by Let's Encrypt and disabled for
  26. new installations since November 2019.
  27. At the moment, Synapse doesn't support ACME v2. For more information and alternative
  28. solutions, please read https://github.com/matrix-org/synapse/blob/master/docs/ACME.md#deprecation-of-acme-v1
  29. --------------------------------------------------------------------------------"""
  30. class AcmeHandler:
  31. def __init__(self, hs):
  32. self.hs = hs
  33. self.reactor = hs.get_reactor()
  34. self._acme_domain = hs.config.acme_domain
  35. async def start_listening(self):
  36. from synapse.handlers import acme_issuing_service
  37. # Configure logging for txacme, if you need to debug
  38. # from eliot import add_destinations
  39. # from eliot.twisted import TwistedDestination
  40. #
  41. # add_destinations(TwistedDestination())
  42. well_known = Resource()
  43. self._issuer = acme_issuing_service.create_issuing_service(
  44. self.reactor,
  45. acme_url=self.hs.config.acme_url,
  46. account_key_file=self.hs.config.acme_account_key_file,
  47. well_known_resource=well_known,
  48. )
  49. responder_resource = Resource()
  50. responder_resource.putChild(b".well-known", well_known)
  51. responder_resource.putChild(b"check", static.Data(b"OK", b"text/plain"))
  52. srv = server.Site(responder_resource)
  53. bind_addresses = self.hs.config.acme_bind_addresses
  54. for host in bind_addresses:
  55. logger.info(
  56. "Listening for ACME requests on %s:%i", host, self.hs.config.acme_port
  57. )
  58. try:
  59. self.reactor.listenTCP(self.hs.config.acme_port, srv, interface=host)
  60. except twisted.internet.error.CannotListenError as e:
  61. check_bind_error(e, host, bind_addresses)
  62. # Make sure we are registered to the ACME server. There's no public API
  63. # for this, it is usually triggered by startService, but since we don't
  64. # want it to control where we save the certificates, we have to reach in
  65. # and trigger the registration machinery ourselves.
  66. self._issuer._registered = False
  67. try:
  68. await self._issuer._ensure_registered()
  69. except Exception:
  70. logger.error(ACME_REGISTER_FAIL_ERROR)
  71. raise
  72. async def provision_certificate(self):
  73. logger.warning("Reprovisioning %s", self._acme_domain)
  74. try:
  75. await self._issuer.issue_cert(self._acme_domain)
  76. except Exception:
  77. logger.exception("Fail!")
  78. raise
  79. logger.warning("Reprovisioned %s, saving.", self._acme_domain)
  80. cert_chain = self._issuer.cert_store.certs[self._acme_domain]
  81. try:
  82. with open(self.hs.config.tls_private_key_file, "wb") as private_key_file:
  83. for x in cert_chain:
  84. if x.startswith(b"-----BEGIN RSA PRIVATE KEY-----"):
  85. private_key_file.write(x)
  86. with open(self.hs.config.tls_certificate_file, "wb") as certificate_file:
  87. for x in cert_chain:
  88. if x.startswith(b"-----BEGIN CERTIFICATE-----"):
  89. certificate_file.write(x)
  90. except Exception:
  91. logger.exception("Failed saving!")
  92. raise
  93. return True