Add certificate expiration to the ke response

This commit is contained in:
Mike Cifelli 2024-03-26 11:19:37 -04:00
parent ac3b7ebcc7
commit 01ab1c1d54
Signed by: mike
GPG Key ID: 6B08C6BE47D08E4C
4 changed files with 64 additions and 11 deletions

View File

@ -0,0 +1,35 @@
defmodule Chronoscope.NTS.Certificate do
def expiration_date(certificate) do
{:Validity, _, {:utcTime, expiration}} =
certificate
|> X509.Certificate.from_der!()
|> X509.Certificate.validity()
cert_time_to_iso8601(expiration)
end
def cert_time_to_iso8601(cert_time) do
captures =
Regex.named_captures(
~r/^(?<year>\d\d)(?<month>\d\d)(?<day>\d\d)(?<hour>\d\d)(?<minute>\d\d)(?<second>\d\d)Z$/,
to_string(cert_time)
)
"#{short_year_to_full_year(captures["year"])}-#{captures["month"]}-#{captures["day"]}T#{captures["hour"]}:#{captures["minute"]}:#{captures["second"]}Z"
end
defp short_year_to_full_year(short_year) do
{century, current_year} =
DateTime.utc_now().year
|> to_string()
|> String.split_at(-2)
if String.to_integer(short_year) >= String.to_integer(current_year) do
century <> short_year
else
century
|> String.to_integer()
|> then(&"#{&1 + 1}#{short_year}")
end
end
end

View File

@ -1,6 +1,7 @@
defmodule Chronoscope.NTS.KeyEstablishmentClient do defmodule Chronoscope.NTS.KeyEstablishmentClient do
require Logger require Logger
alias Chronoscope.NTS.Certificate
alias Chronoscope.NTS.KeyEstablishmentRequest alias Chronoscope.NTS.KeyEstablishmentRequest
alias Chronoscope.NTS.KeyEstablishmentResponse alias Chronoscope.NTS.KeyEstablishmentResponse
@ -36,7 +37,7 @@ defmodule Chronoscope.NTS.KeyEstablishmentClient do
:ssl.close(socket) :ssl.close(socket)
case KeyEstablishmentResponse.parse(response) do case KeyEstablishmentResponse.parse(response) do
{:ok, x} -> {:ok, Map.put(x, :cert_expiration, certificate_expiration(peercert))} {:ok, parsed_response} -> {:ok, Map.put(parsed_response, :cert_expiration, Certificate.expiration_date(peercert))}
# todo - indicate errors in server response # todo - indicate errors in server response
error -> error error -> error
end end
@ -52,13 +53,4 @@ defmodule Chronoscope.NTS.KeyEstablishmentClient do
{:error, :timeout} {:error, :timeout}
end end
end end
defp certificate_expiration(certificate) do
{:Validity, _, {:utcTime, expiration}} =
certificate
|> X509.Certificate.from_der!()
|> X509.Certificate.validity()
expiration
end
end end

View File

@ -22,7 +22,7 @@ defmodule ChronoscopeWeb.API.V1.NTS.KeyEstablishmentController do
defp format_response(response) do defp format_response(response) do
response response
|> Map.take([:aead_algorithms, :cookie_length, :cookies, :next_protocols, :port, :server]) |> Map.take([:aead_algorithms, :cert_expiration, :cookie_length, :cookies, :next_protocols, :port, :server])
|> Map.update(:cookies, 0, &length/1) |> Map.update(:cookies, 0, &length/1)
end end
end end

View File

@ -0,0 +1,26 @@
defmodule Chronoscope.NTS.CertificateTest do
use ExUnit.Case
import Chronoscope.NTS.Certificate
test "parses the expiration date of a certificate" do
{:ok, expiration, _} =
:secp256r1
|> X509.PrivateKey.new_ec()
|> X509.Certificate.self_signed("/C=US/ST=CA/L=San Francisco/O=Acme/CN=Test", validity: 12)
|> X509.Certificate.to_der()
|> expiration_date()
|> DateTime.from_iso8601()
assert DateTime.diff(expiration, DateTime.utc_now(), :day) == 12
end
# todo - mock current time
test "converts certificate datetime to iso8601" do
assert cert_time_to_iso8601("240326110000Z") == "2024-03-26T11:00:00Z"
end
test "handles century rollover" do
assert cert_time_to_iso8601("010326110000Z") == "2101-03-26T11:00:00Z"
end
end