Current section
Files
Jump to
Current section
Files
lib/services/crt.ex
defmodule CA.CRT do
@moduledoc "X.509 Certificates."
def baseLength(oid) when is_tuple(oid) do
CA.Curve.getLength(CA.KnownCurves.getCurveByOid(oid))
end
def baseLength(_) do
256
end
# Rivest-Shamir-Adleman schema of Diffie–Hellman key exchange
def decodeRSA(_, _, publicKey) do
{:ok, key} = :"PKCS-1".decode(:RSAPublicKey, publicKey)
[
key: key,
scheme: :RSA
]
end
# Integers over Prime Galois Fields GF(p)
def decodeECC(agreement, parameters, publicKey) do
params = CA.CE.decodeObjectIdentifier(parameters)
bin = :binary.part(publicKey, 1, :erlang.size(publicKey) - 1)
baseLength = baseLength(params)
xs = :binary.part(bin, 0, baseLength)
ys = :binary.part(bin, baseLength, :erlang.size(bin) - baseLength)
[
x: CA.ECDSA.numberFromString(xs),
y: CA.ECDSA.numberFromString(ys),
scheme: CA.AT.oid(agreement),
curve: CA.AT.oid(params)
]
end
# Polynomials over Binary Galois Fields GF(2^m)
def decodeGFE(agreement, params, publicKey) do
{:ok, p} = :DSTU.decode(:DSTU4145Params, params)
[
key: publicKey,
scheme: CA.AT.oid(agreement),
field: p
]
end
def decodePublicKey(agreement, {:asn1_OPENTYPE, params}, publicKey) do
decodePublicKey(agreement, params, publicKey)
end
def decodePublicKey(agreement, params, publicKey) do
case agreement do
{1, 2, 840, 113_549, 1, 1, 1} ->
decodeRSA(agreement, params, publicKey)
{1, 2, 840, 10045, 2, 1} ->
decodeECC(agreement, params, publicKey)
{1, 2, 804, 2, 1, 1, 1, 1, 3, 1, 1} ->
decodeGFE(agreement, params, publicKey)
_ ->
:logger.info(~c"new unknown publicKey agreement scheme detected: ~p~n", [agreement])
:base64.encode(publicKey)
end
end
def parseCertPEM(file) do
{:ok, bin} = :file.read_file(file)
list = :public_key.pem_decode(bin)
:lists.map(fn x -> parseCert(:public_key.pem_entry_decode(x)) end, list)
end
def parseCertB64(file) do
{:ok, bin} = :file.read_file(file)
parseCertBin97(:base64.decode(bin))
end
def parseCertFile(file) do
{:ok, bin} = :file.read_file(file)
parseCertBin97(bin)
end
def parseCertBin97(bin) do
{:ok, cert} = :AuthenticationFramework.decode(:Certificate, bin)
parseCert(cert)
end
def parseCertBin88(bin) do
{:ok, cert} = :PKIX1Explicit88.decode(:Certificate, bin)
parseCert(cert)
end
def parseCert(cert, _) do
parseCert(cert)
end
def parseCert({:certificate, cert}) do
parseCert(cert)
end
def parseCert(cert) do
{:Certificate, tbs, _, _} =
case cert do
{:Certificate, tbs, x, y} -> {:Certificate, tbs, x, y}
{:Certificate, tbs, x, y, _} -> {:Certificate, tbs, x, y}
end
{_, ver, serial, {_, alg, _}, issuer, {_, {_, nb}, {_, na}}, issuee,
{:SubjectPublicKeyInfo, {_, agreement, params}, publicKey}, _b, _c, exts} = tbs
extensions =
:lists.map(
fn {:Extension, code, _x, b} ->
CA.CE.oid(code, :lists.flatten(CA.CE.flat(code, :asn1rt_nif.decode_ber_tlv(b), [])))
end,
exts
)
[
resourceType: :Certificate,
version: ver,
signatureAlgorithm: CA.AT.code(alg),
subject: CA.RDN.rdn(CA.RDN.decodeAttrs(issuee)),
issuer: CA.RDN.rdn(CA.RDN.decodeAttrs(issuer)),
serial: :base64.encode(CA.CE.integer(serial)),
validity: [from: nb, to: na],
publicKey: decodePublicKey(agreement, params, publicKey),
extensions: extensions
]
end
end