Skip to content
Browse files

Add support for specifying signer key expiration

  • Loading branch information...
fhunleth authored and mobileoverlord committed Dec 22, 2018
1 parent cf623bc commit 21c54f68b94e3b26c13345a481a8fb6b654fd07b
Showing with 41 additions and 9 deletions.
  1. +8 −6 lib/mix/tasks/nerves_key.signer.ex
  2. +12 −3 lib/nerves_key.ex
  3. +21 −0 test/nerves_key_test.exs
@@ -9,14 +9,16 @@ defmodule Mix.Tasks.NervesKey.Signer do
## create
Create a new NervesKey signing certificate and private key pair. This
creates a compressable X.509 certificate that can be stored in the
creates a compressible X.509 certificate that can be stored in the
ATECC508A's limited memory.
mix nerves_key.signer create NAME
mix nerves_key.signer create NAME --years-valid <YEARS>
If --years-valid is unspecified, the new certificate will be valid for
one year.

@switches []
@switches [years_valid: :integer]

def run(args) do
{opts, args} = OptionParser.parse!(args, strict: @switches)
@@ -36,14 +38,14 @@ defmodule Mix.Tasks.NervesKey.Signer do
Invalid arguments to `mix nerves_key.signer`.
mix nerves_key.key create NAME
mix nerves_key.key create NAME --years-valid <YEARS>
Run `mix help nerves_key.signer` for more information.

@spec create(String.t(), keyword()) :: :ok
def create(name, _opts) do
def create(name, opts) do
cert_path = name <> ".cert"
key_path = name <> ".key"

@@ -55,7 +57,7 @@ defmodule Mix.Tasks.NervesKey.Signer do
Mix.raise("Refusing to overwrite #{key_path}. Please remove or change the name")

{cert, priv_key} = NervesKey.create_signing_key_pair()
{cert, priv_key} = NervesKey.create_signing_key_pair(opts)
pem_cert = X509.Certificate.to_pem(cert)
pem_key = X509.PrivateKey.to_pem(priv_key)

@@ -22,14 +22,23 @@ defmodule NervesKey do
@doc """
Create a signing key pair
This returns a tuple that contains the certificate and the private key.
This returns a tuple that contains a new signer certificate and private key.
It is compatible with the ATECC508A certificate compression.
* :years_valid - how many years this signing key is valid for
def create_signing_key_pair() do
@spec create_signing_key_pair(keyword()) :: {X509.Certificate.t(), X509.PrivateKey.t()}
def create_signing_key_pair(opts \\ []) do
years_valid = Keyword.get(opts, :years_valid, 1)

@doc """
Read the device certificate from the slot
The device must be programmed for this to work.
@spec device_cert(ATECC508A.Transport.t()) :: X509.Certificate.t()
def device_cert(transport) do
@@ -0,0 +1,21 @@
defmodule NervesKeyTest do
use ExUnit.Case

import X509.ASN1

test "create signer cert" do
{cert, _key} = NervesKey.create_signing_key_pair()
validity(notBefore: nb, notAfter: na) = X509.Certificate.validity(cert)
assert year(na) - year(nb) == 1

{cert, _key} = NervesKey.create_signing_key_pair(years_valid: 5)
validity(notBefore: nb, notAfter: na) = X509.Certificate.validity(cert)
assert year(na) - year(nb) == 5

defp year({:utcTime, [a, b | _]}) do
[a, b]
|> to_string()
|> String.to_integer()

0 comments on commit 21c54f6

Please sign in to comment.
You can’t perform that action at this time.