pem_info.hpp 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. #pragma once
  2. #include <string>
  3. #include <vector>
  4. #include <nlohmann/json.hpp>
  5. #include "common/error.hpp"
  6. namespace smartbotic::certs {
  7. // What a stored certificate actually is, read out of the PEM rather than
  8. // typed in beside it. The API refuses a PEM it cannot parse, and the UI shows
  9. // these so an expiry is visible before it becomes a confusing TLS error at
  10. // three in the morning.
  11. struct CertificateInfo {
  12. std::string subject;
  13. std::string issuer;
  14. int64_t not_before_ms = 0;
  15. int64_t not_after_ms = 0;
  16. // Uppercase hex, colon separated - the form openssl x509 -fingerprint
  17. // prints, so it can be compared against a server by eye.
  18. std::string fingerprint_sha256;
  19. // A trust anchor is normally a CA. A leaf certificate can be pinned as an
  20. // anchor too and OpenSSL accepts it, so this is reported rather than
  21. // enforced.
  22. bool is_ca = false;
  23. nlohmann::json toJson() const;
  24. };
  25. // Every certificate in a PEM bundle, in file order. A bundle is allowed: an
  26. // internal CA is often issued under a root that has to travel with it.
  27. //
  28. // Failure means nothing in the input parsed as a certificate. The caller
  29. // refuses the input rather than storing it - a PEM that is silently kept and
  30. // silently ignored at request time is the shape of bug this whole feature
  31. // exists to avoid.
  32. common::Result<std::vector<CertificateInfo>> parsePem(const std::string& pem);
  33. // Whether a request's host is one this certificate was assigned to.
  34. //
  35. // Exact match, or a single leading "*." wildcard that matches exactly one
  36. // label - "*.fsociety.hu" covers "api.fsociety.hu" but not "fsociety.hu" and
  37. // not "a.b.fsociety.hu", which is how certificate wildcards themselves work.
  38. // Comparison is case-insensitive; a trailing dot on either side is ignored.
  39. //
  40. // This lives here, next to the parsing, because the webserver validates
  41. // patterns with it and the runner decides with it. Two implementations of one
  42. // matching rule is exactly how a host quietly ends up trusted in one place and
  43. // not the other.
  44. bool hostMatches(const std::string& host, const std::vector<std::string>& patterns);
  45. } // namespace smartbotic::certs