Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions lib/cfxxl.ex
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ defmodule CFXXL do
@scan_opts [:ip, :timeout, :family, :scanner]
@sign_opts [:hosts, :subject, :serial_sequence, :label, :profile, :bundle]

@spec authsign(CFXXL.Client.t(), String.t(), String.t(), keyword() | nil) ::
{:ok, any()} | {:error, any()}
@doc """
Request to sign a CSR with authentication.

Expand Down Expand Up @@ -65,6 +67,7 @@ defmodule CFXXL do
post(client, "authsign", body)
end

@spec bundle(CFXXL.Client.t(), keyword()) :: {:ok, any()} | {:error, any()}
@doc """
Request a certificate bundle

Expand Down Expand Up @@ -127,6 +130,7 @@ defmodule CFXXL do

def bundle(_client, _opts), do: {:error, :no_certificate_or_domain}

@spec certinfo(CFXXL.Client.t(), keyword()) :: {:ok, any()} | {:error, any()}
@doc """
Request information about a certificate

Expand Down Expand Up @@ -161,6 +165,7 @@ defmodule CFXXL do

def certinfo(_client, _opts), do: {:error, :no_certificate_or_domain}

@spec crl(CFXXL.Client.t(), String.t() | nil) :: {:ok, any()} | {:error, any()}
@doc """
Generate a CRL from the database

Expand All @@ -181,6 +186,7 @@ defmodule CFXXL do
end
end

@spec get(CFXXL.Client.t(), String.t(), map() | nil) :: {:ok, any()} | {:error, any()}
@doc """
Perform a generic GET to the CFSSL API.

Expand All @@ -199,6 +205,7 @@ defmodule CFXXL do
|> process_response()
end

@spec info(CFXXL.Client.t(), String.t(), keyword() | nil) :: {:ok, any()} | {:error, any()}
@doc """
Get signer information

Expand All @@ -225,6 +232,8 @@ defmodule CFXXL do
post(client, "info", body)
end

@spec init_ca(CFXXL.Client.t(), list(String.t()), CFXXL.DName.t(), keyword() | nil) ::
{:ok, any()} | {:error, any()}
@doc """
Request a new CA key/certificate pair.

Expand Down Expand Up @@ -253,6 +262,8 @@ defmodule CFXXL do
post(client, "init_ca", body)
end

@spec newcert(CFXXL.Client.t(), list(String.t()), CFXXL.DName.t(), keyword() | nil) ::
{:ok, any()} | {:error, any()}
@doc """
Request a new key/signed certificate pair.

Expand Down Expand Up @@ -285,6 +296,8 @@ defmodule CFXXL do
post(client, "newcert", body)
end

@spec newkey(CFXXL.Client.t(), list(String.t()), CFXXL.DName.t(), keyword() | nil) ::
{:ok, any()} | {:error, any()}
@doc """
Request a new key/CSR pair.

Expand All @@ -309,6 +322,7 @@ defmodule CFXXL do
post(client, "newkey", body)
end

@spec post(CFXXL.Client.t(), String.t(), map()) :: {:ok, any()} | {:error, any()}
@doc """
Perform a generic POST to the CFSSL API.

Expand All @@ -328,6 +342,7 @@ defmodule CFXXL do
|> process_response()
end

@spec revoke(CFXXL.Client.t(), String.t(), String.t(), String.t()) :: :ok | {:error, any()}
@doc """
Request to revoke a certificate.

Expand All @@ -351,6 +366,7 @@ defmodule CFXXL do
end
end

@spec scan(CFXXL.Client.t(), String.t(), keyword() | nil) :: {:ok, any()} | {:error, any()}
@doc """
Scan an host

Expand Down Expand Up @@ -378,6 +394,7 @@ defmodule CFXXL do
get(client, "scan", params)
end

@spec scaninfo(CFXXL.Client.t()) :: {:ok, any()} | {:error, any()}
@doc """
Get information on scan families

Expand All @@ -392,6 +409,7 @@ defmodule CFXXL do
get(client, "scaninfo")
end

@spec sign(CFXXL.Client.t(), String.t(), keyword() | nil) :: {:ok, any()} | {:error, any()}
@doc """
Request to sign a CSR.

Expand Down Expand Up @@ -426,6 +444,8 @@ defmodule CFXXL do
defp process_response({:error, _} = response), do: response
defp process_response({:ok, %HTTPoison.Response{body: body}}), do: extract_result(body)

@spec extract_result(iodata) ::
{:ok, any()} | {:error, any()}
defp extract_result(""), do: {:error, :empty_response}

defp extract_result(body) do
Expand All @@ -436,30 +456,35 @@ defmodule CFXXL do
end
end

@spec extract_error_message(%{required(String.t()) => list()}) :: String.t()
defp extract_error_message(%{"errors" => errors}) do
case errors do
[%{"message" => msg} | _] -> msg
[] -> :generic_error
end
end

@spec normalize_aki(String.t()) :: String.t()
defp normalize_aki(aki) do
aki
|> String.downcase()
|> String.replace(":", "")
end

@spec filter_opts(keyword(), list()) :: keyword()
defp filter_opts(opts, accepted_opts) do
opts
|> Enum.filter(fn {k, _} -> k in accepted_opts end)
end

@spec newkey_request(list(), DName.t(), keyword()) :: map()
defp newkey_request(hosts, dname, opts) do
opts
|> filter_opts(@newkey_opts)
|> Enum.into(%{hosts: hosts, names: dname})
end

@spec sign_request(any(), keyword()) :: map()
defp sign_request(csr, opts) do
opts
|> filter_opts(@sign_opts)
Expand Down
6 changes: 6 additions & 0 deletions lib/cfxxl/ca_config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ defmodule CFXXL.CAConfig do
"""
defstruct [:pathlength, :pathlenzero, :expiry]

@type t() :: %__MODULE__{
pathlength: non_neg_integer(),
pathlenzero: boolean(),
expiry: String.t()
}

defimpl Jason.Encoder, for: CFXXL.CAConfig do
def encode(ca_config, options) do
# Encode only non-nil values
Expand Down
9 changes: 9 additions & 0 deletions lib/cfxxl/cert_utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ defmodule CFXXL.CertUtils do
Record.extract(:Validity, from_lib: "public_key/include/public_key.hrl")
)

@spec serial_number!(String.t()) :: String.t()
@doc """
Extracts the serial number of a certificate.

Expand All @@ -77,6 +78,7 @@ defmodule CFXXL.CertUtils do
|> to_string()
end

@spec authority_key_identifier!(String.t()) :: String.t()
@doc """
Extracts the authority key identifier of a certificate.

Expand All @@ -103,6 +105,7 @@ defmodule CFXXL.CertUtils do
end
end

@spec common_name!(String.t()) :: String.t() | nil
@doc """
Extracts the Common Name of a certificate.

Expand Down Expand Up @@ -134,6 +137,7 @@ defmodule CFXXL.CertUtils do
end
end

@spec not_after!(String.t()) :: DateTime.t()
@doc """
Extracts the not_after field (expiration) of a certificate.

Expand All @@ -149,6 +153,7 @@ defmodule CFXXL.CertUtils do
|> cert_time_tuple_to_datetime()
end

@spec not_before!(String.t()) :: DateTime.t()
@doc """
Extracts the not_before field of a certificate.

Expand All @@ -164,6 +169,8 @@ defmodule CFXXL.CertUtils do
|> cert_time_tuple_to_datetime()
end

@spec cert_time_tuple_to_datetime({:utcTime | :generalTime, iolist()}) ::
DateTime.t()
defp cert_time_tuple_to_datetime({:utcTime, [y0, y1 | _rest] = time_charlist}) do
short_year = parse_charlist_int([y0, y1])

Expand Down Expand Up @@ -192,6 +199,7 @@ defmodule CFXXL.CertUtils do
DateTime.from_naive!(naive, "Etc/UTC")
end

@spec parse_charlist_int(iolist()) :: integer()
defp parse_charlist_int(charlist) do
{parsed, ""} =
charlist
Expand All @@ -201,6 +209,7 @@ defmodule CFXXL.CertUtils do
parsed
end

@spec tbs(binary) :: any
defp tbs(cert) do
cert
|> :public_key.pem_decode()
Expand Down
7 changes: 7 additions & 0 deletions lib/cfxxl/client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ defmodule CFXXL.Client do
"""
defstruct endpoint: "http://localhost:8888/#{@api_prefix}", options: []

@type t() :: %__MODULE__{
endpoint: String.t(),
options: HTTPoison.Request.options()
}

@spec new :: CFXXL.Client.t()
@doc """
Returns a default client

Expand All @@ -42,6 +48,7 @@ defmodule CFXXL.Client do
"""
def new(), do: %__MODULE__{}

@spec new(String.t(), HTTPoison.Request.options() | nil) :: CFXXL.Client.t()
@doc """
Creates a client with the given parameters.

Expand Down
8 changes: 8 additions & 0 deletions lib/cfxxl/dname.ex
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ defmodule CFXXL.DName do
"""
defstruct [:C, :L, :O, :OU, :ST]

@type t() :: %__MODULE__{
C: String.t(),
L: String.t(),
O: String.t(),
OU: String.t(),
ST: String.t()
}

defimpl Jason.Encoder, for: CFXXL.DName do
def encode(dname, options) do
# Encode only non-nil values
Expand Down
5 changes: 5 additions & 0 deletions lib/cfxxl/key_config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,9 @@ defmodule CFXXL.KeyConfig do
* 521
"""
defstruct algo: :ecdsa, size: 256

@type t() :: %__MODULE__{
algo: :ecdsa | :rsa,
size: pos_integer()
}
end
5 changes: 5 additions & 0 deletions lib/cfxxl/subject.ex
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ defmodule CFXXL.Subject do
"""
defstruct [:CN, :dname]

@type t() :: %__MODULE__{
CN: String.t(),
dname: CFXXL.DName.t()
}

defimpl Jason.Encoder, for: CFXXL.Subject do
def encode(subject, options) do
# Encode only non-nil values and substitute dname
Expand Down
16 changes: 14 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ defmodule CFXXL.Mixfile do
"coveralls.detail": :test,
"coveralls.post": :test,
"coveralls.html": :test
]
],

# Dyalizer cache
dialyzer_cache_directory: dialyzer_cache_directory(Mix.env())
]
end

Expand All @@ -36,6 +39,14 @@ defmodule CFXXL.Mixfile do
[extra_applications: [:logger]]
end

defp dialyzer_cache_directory(:ci) do
"dialyzer_cache"
end

defp dialyzer_cache_directory(_) do
nil
end

# Dependencies can be Hex packages:
#
# {:my_dep, "~> 0.3.0"}
Expand All @@ -50,7 +61,8 @@ defmodule CFXXL.Mixfile do
{:httpoison, "~> 1.6"},
{:jason, "~> 1.2"},
{:ex_doc, ">= 0.0.0", only: :dev, runtime: false},
{:excoveralls, "~> 0.12", only: :test}
{:excoveralls, "~> 0.12", only: :test},
{:dialyzex, github: "Comcast/dialyzex", only: [:dev, :ci]}
]
end

Expand Down
33 changes: 17 additions & 16 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
%{
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.21.3", "857ec876b35a587c5d9148a2512e952e24c24345552259464b98bfbb883c7b42", [:mix], [{:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"excoveralls": {:hex, :excoveralls, "0.12.3", "2142be7cb978a3ae78385487edda6d1aff0e482ffc6123877bb7270a8ffbcfe0", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
"hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
"httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"jason": {:hex, :jason, "1.2.0", "10043418c42d2493d0ee212d3fddd25d7ffe484380afad769a0a38795938e448", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"makeup": {:hex, :makeup, "1.0.1", "82f332e461dc6c79dbd82fbe2a9c10d48ed07146f0a478286e590c83c52010b5", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
"makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"},
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "805abd97539caf89ec6d4732c91e62ba9da0cda51ac462380bbd28ee697a8c42"},
"dialyzex": {:git, "https://github.com/Comcast/dialyzex.git", "cdc7cf71fe6df0ce4cf59e3f497579697a05c989", []},
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"},
"ex_doc": {:hex, :ex_doc, "0.21.3", "857ec876b35a587c5d9148a2512e952e24c24345552259464b98bfbb883c7b42", [:mix], [{:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "0db1ee8d1547ab4877c5b5dffc6604ef9454e189928d5ba8967d4a58a801f161"},
"excoveralls": {:hex, :excoveralls, "0.12.3", "2142be7cb978a3ae78385487edda6d1aff0e482ffc6123877bb7270a8ffbcfe0", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "568a3e616c264283f5dea5b020783ae40eef3f7ee2163f7a67cbd7b35bcadada"},
"hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "e0100f8ef7d1124222c11ad362c857d3df7cb5f4204054f9f0f4a728666591fc"},
"httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "aa2c74bd271af34239a3948779612f87df2422c2fdcfdbcec28d9c105f0773fe"},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"},
"jason": {:hex, :jason, "1.2.0", "10043418c42d2493d0ee212d3fddd25d7ffe484380afad769a0a38795938e448", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "116747dbe057794c3a3e4e143b7c8390b29f634e16c78a7f59ba75bfa6852e7f"},
"makeup": {:hex, :makeup, "1.0.1", "82f332e461dc6c79dbd82fbe2a9c10d48ed07146f0a478286e590c83c52010b5", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "49736fe5b66a08d8575bf5321d716bac5da20c8e6b97714fec2bcd6febcfa1f8"},
"makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "d4b316c7222a85bbaa2fd7c6e90e37e953257ad196dc229505137c5e505e9eff"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm", "13104d7897e38ed7f044c4de953a6c28597d1c952075eb2e328bc6d6f2bfc496"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"},
}