lib/kep.ex

defmodule CA.KEP do
  require Record

  Record.defrecord(:certAttrs, serial: "", cn: "", givenName: "", surname: "", o: "", title: "", ou: "", c: "", locality: "")

  def extract(code, person) do
    case :lists.keyfind(code, 2, person) do
      false -> ""
      {_, _, {:printable, str}} -> str
      {_, _, {:utf8, str}} -> str
    end
  end

  def parseSignData(bin) do
    {_, {:ContentInfo, _, ci}} = :KEP.decode(:ContentInfo, bin)
    {:ok, {:SignedData, _, alg, x, c, x1, x2}} = :KEP.decode(:SignedData, ci)
    parseSignDataCert({alg,x,c,x1,x2})
  end

  def parseSignDataCert({_,_,:asn1_NOVALUE,_,_}), do: []
  def parseSignDataCert({_,_,[cert],_,_}), do: parseCert(cert)

  def parseAttrs(attrs) do
    certAttrs(
      o: extract({2, 5, 4, 10}, attrs),
      ou: extract({2, 5, 4, 11}, attrs),
      title: extract({2, 5, 4, 12}, attrs),
      cn: extract({2, 5, 4, 3}, attrs),
      givenName: extract({2, 5, 4, 42}, attrs),
      surname: extract({2, 5, 4, 4}, attrs),
      locality: extract({2, 5, 4, 7}, attrs),
      serial: extract({2, 5, 4, 5}, attrs),
      c: extract({2, 5, 4, 6}, attrs)
    )
  end

  def pair([],acc), do: acc
  def pair([x],acc), do: [x|acc]
  def pair([a,b|t],acc), do: pair(t,[{:oid.decode(a),b}|acc])

  def oid({1,3,6,1,5,5,7,1,1}, v), do: {:authorityInfoAccess, pair(v,[])}
  def oid({1,3,6,1,5,5,7,1,3}, [v]), do: {:qcStatements, :oid.decode v}
  def oid({1,3,6,1,5,5,7,1,11},v), do: {:subjectInfoAccess, pair(v,[])}
  def oid({2,5,29,9},v),  do: {:subjectDirectoryAttributes, pair(v,[])}
  def oid({2,5,29,14},v), do: {:subjectKeyIdentifier, pair(v,[])}
  def oid({2,5,29,15},v), do: {:keyUsage, pair(v,[])}
  def oid({2,5,29,16},v), do: {:privateKeyUsagePeriod, v}
  def oid({2,5,29,17},v), do: {:subjectAltName, pair(v,[])}
  def oid({2,5,29,19},v), do: {:basicConstraints, pair(v,[])}
  def oid({2,5,29,31},v), do: {:cRLDistributionPoints, pair(v,[])}
  def oid({2,5,29,32},[v]), do: {:certificatePolicies, :oid.decode v}
  def oid({2,5,29,35},v), do: {:authorityKeyIdentifier, pair(v,[])}
  def oid({2,5,29,46},v), do: {:freshestCRL, pair(v,[])}
  def oid(x,v) when is_binary(x), do: {:oid.decode(x),pair(v,[])}
  def oid(x,v), do: {x,v}

  def flat(code,{k,v},acc) when is_integer(k), do: [flat(code,v,acc)|acc]
  def flat(code,{k,_v},acc), do: [flat(code,k,acc)|acc]
  def flat(code,k,acc) when is_list(k), do: [:lists.map(fn x -> flat(code,x,acc) end, k)|acc]
  def flat(_code,k,acc) when is_binary(k), do: [k|acc]

  def parseCert(cert) do
    {:Certificate, a, _, _} = cert
    {:Certificate_toBeSigned, _ver, _sel, _alg, issuer, _val, issuee, _, _, _, exts} = a
    extensions = :lists.map(fn {:Extension,code,_,b} ->
         oid(code, :lists.flatten(flat(code,:asn1rt_nif.decode_ber_tlv(b),[])))
      end, exts)
    person = :lists.flatten(:erlang.element(2, issuee))
    ca = :lists.flatten(:erlang.element(2, issuer))
    {parseAttrs(person),parseAttrs(ca),extensions}
  end
end