Skip to content

Commit d192d17

Browse files
committed
Add in arguments for supporting base64 serialization and domain name extraction
1 parent b43b417 commit d192d17

3 files changed

Lines changed: 71 additions & 6 deletions

File tree

lib/easy_ssl.ex

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,56 @@ defmodule EasySSL do
5858
}
5959
}
6060
"""
61-
def parse_der(certificate_der) when is_binary(certificate_der) do
61+
def parse_der(certificate_der, opts \\ [all_domains: false, serialize: false]) when is_binary(certificate_der) do
6262
cert = :public_key.pkix_decode_cert(certificate_der, :otp) |> get_field(:tbsCertificate)
6363

64-
%{}
64+
serialized_certificate = %{}
6565
|> Map.put(:fingerprint, certificate_der |> fingerprint_cert)
6666
|> Map.put(:serial_number, cert |> get_field(:serialNumber) |> Integer.to_string(16))
6767
|> Map.put(:subject, cert |> parse_subject)
6868
|> Map.put(:extensions, cert |> parse_extensions)
6969
|> Map.merge(parse_expiry(cert))
70+
71+
Enum.reduce(opts, serialized_certificate, fn {option, flag}, serialized_certificate ->
72+
case option do
73+
:all_domains when flag == true ->
74+
serialized_certificate
75+
|> Map.put(:all_domains, get_all_domain_names(cert, serialized_certificate))
76+
77+
:serialize when flag == true ->
78+
serialized_certificate
79+
|> Map.put(:as_der, Base.encode64(certificate_der))
80+
_ -> serialized_certificate
81+
end
82+
end)
83+
end
84+
85+
def get_all_domain_names(cert, serialized_cert) do
86+
domain_names = MapSet.new()
87+
88+
domain_names = case serialized_cert[:subject][:CN] do
89+
nil -> domain_names
90+
_ -> MapSet.put(domain_names, serialized_cert[:subject][:CN])
91+
end
92+
93+
extensions = cert |> get_field(:extensions)
94+
95+
extensions
96+
|> Enum.reduce(domain_names, fn extension, domain_names ->
97+
case extension do
98+
{:Extension, {2, 5, 29, 17}, _critical, san_entries} ->
99+
san_entries
100+
|> Enum.reduce(domain_names, fn entry, names ->
101+
case entry do
102+
{:dNSName, dns_name} -> MapSet.put(names, dns_name |> to_string)
103+
_ -> names
104+
end
105+
end)
106+
:asn1_NOVALUE -> domain_names
107+
_ -> domain_names
108+
end
109+
end)
110+
|> MapSet.to_list
70111
end
71112

72113
@doc """
@@ -104,7 +145,7 @@ defmodule EasySSL do
104145
}
105146
"""
106147
def parse_pem(cert_charlist) when is_list(cert_charlist) do parse_pem(cert_charlist |> to_string) end
107-
def parse_pem(cert_pem) do
148+
def parse_pem(cert_pem, opts \\ [all_domains: false, return_base64: false]) do
108149
cert_regex = ~r/^\-{5}BEGIN\sCERTIFICATE\-{5}\n(?<certificate>[^\-]+)\-{5}END\sCERTIFICATE\-{5}/
109150
match = Regex.named_captures(cert_regex, cert_pem)
110151

@@ -115,7 +156,7 @@ defmodule EasySSL do
115156
match["certificate"]
116157
|> String.replace("\n", "")
117158
|> Base.decode64!
118-
|> parse_der
159+
|> parse_der(opts)
119160
end
120161

121162
defp get_field(record, field) do
@@ -284,7 +325,7 @@ defmodule EasySSL do
284325

285326
# Basically ignore those
286327
{:directoryName, _sequence} -> san_list
287-
{:otherName, other_name} -> san_list
328+
{:otherName, _sequence} -> san_list
288329

289330
_ ->
290331
raise("Unhandled SAN entry type #{inspect entry}")

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ defmodule EasySSL.MixProject do
55
[
66
app: :easy_ssl,
77
name: "EasySSL",
8-
version: "1.0.2",
8+
version: "1.0.3",
99
elixir: "~> 1.6",
1010
description: "SSL/X509 parsing for humans.",
1111
deps: deps(),

test/easy_ssl_test.exs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,28 @@ defmodule EasySSLTest do
5757
assert_has_normal_atom_keys(cert)
5858
end
5959

60+
test "parses and adds all domains to the top level leaf node" do
61+
cert_bytes = File.read!(@der_cert_dir <> "twitter.com.der")
62+
63+
serialized_cert = cert_bytes
64+
|> EasySSL.parse_der()
65+
refute Enum.member?(Map.keys(serialized_cert), :as_der)
66+
refute Enum.member?(Map.keys(serialized_cert), :all_domains)
67+
68+
serialized_cert = cert_bytes
69+
|> EasySSL.parse_der(all_domains: true)
70+
refute Enum.member?(Map.keys(serialized_cert), :as_der)
71+
assert Enum.member?(Map.keys(serialized_cert), :all_domains)
72+
73+
serialized_cert = cert_bytes
74+
|> EasySSL.parse_der(serialize: true)
75+
assert Enum.member?(Map.keys(serialized_cert), :as_der)
76+
refute Enum.member?(Map.keys(serialized_cert), :all_domains)
77+
78+
serialized_cert = cert_bytes
79+
|> EasySSL.parse_der(serialize: true, all_domains: true)
80+
assert Enum.member?(Map.keys(serialized_cert), :as_der)
81+
assert Enum.member?(Map.keys(serialized_cert), :all_domains)
82+
end
83+
6084
end

0 commit comments

Comments
 (0)