From d9b6707c53a93b5ad6236f4485b83e17518372dc Mon Sep 17 00:00:00 2001 From: 5HT Date: Wed, 30 Oct 2024 22:04:31 +0200 Subject: [PATCH] wip --- lib/encryption/cms.ex | 14 ++++++++++++++ lib/oid/alg.ex | 31 ++++++++++++++++++++++++------- lib/services/cmp.ex | 6 +++--- lib/services/crt.ex | 31 +++++++++++++++---------------- lib/signing/ecdsa.ex | 6 ------ src/oid.erl | 33 +++++++++++++++++++++++++++++++++ 6 files changed, 89 insertions(+), 32 deletions(-) create mode 100644 src/oid.erl diff --git a/lib/encryption/cms.ex b/lib/encryption/cms.ex index 243b87f..432ca4a 100644 --- a/lib/encryption/cms.ex +++ b/lib/encryption/cms.ex @@ -146,4 +146,18 @@ defmodule CA.CMS do CA.AES.decrypt(:'id-aes256-CBC', data, unwrap, iv) end + def parseSignDataFile(file) do + {_, bin} = :file.read_file file + parseSignData(bin) + end + + def parseSignData(bin) do + {_, {:ContentInfo, oid, ci}} = :KEP.decode(:ContentInfo, bin) + {:ok, {:SignedData, a, alg, x, c, x1, si}} = :KEP.decode(:SignedData, ci) + {:SignedData, a, alg, x, parseSignDataCert({alg,oid,x,c,x1,si}), x1, si} + end + + def parseSignDataCert({_,_,_,:asn1_NOVALUE,_,_}), do: [] + def parseSignDataCert({_,_,_,certs,_,si}), do: :lists.map(fn cert -> CA.CRT.parseCert(cert, si) end, certs) + end \ No newline at end of file diff --git a/lib/oid/alg.ex b/lib/oid/alg.ex index 7c8852a..44f8bcb 100644 --- a/lib/oid/alg.ex +++ b/lib/oid/alg.ex @@ -5,13 +5,30 @@ defmodule CA.ALG do def lookup(oid), do: :lists.keyfind(oid, 2, algorithms()) def algorithms() do [ - {:'id-PasswordBasedMac', {1,2,840,113533,7,66,13}}, - {:'id-DHBasedMac', {1,2,840,113533,7,66,30}}, - {:'id-gost28147-ofb', {1,2,804,2,1,1,1,1,1,1,2}}, - {:'id-gost28147-cfb', {1,2,804,2,1,1,1,1,1,1,3}}, - {:'id-gost28147-wrap', {1,2,804,2,1,1,1,1,1,1,5}}, - {:'id-Dstu7624cfb-x256', {1,2,804,2,1,1,1,1,1,3,3,2}}, - {:'id-Dstu7624ofb-x256', {1,2,804,2,1,1,1,1,1,3,6,2}}, + {:iitStoreOID, {1,3,6,1,4,1,19398,1,1,1,2}}, + {:dstu4145Curve, {1,3,6,1,4,1,19398,1,1,2,2}}, + {:dstu4145Key, {1,3,6,1,4,1,19398,1,1,2,3}}, + {"iit", {1,3,6,1,4,1,19398,1,1,4,1}}, + {:pbes1, {1,3,6,1,4,1,42,2,19,1}}, + {:keyProtector, {1,3,6,1,4,1,42,2,17,1,1}}, + {:'id-PasswordBasedMac', {1,2,840,113533,7,66,13}}, + {:'id-DHBasedMac', {1,2,840,113533,7,66,30}}, + {:'id-gost28147-ofb', {1,2,804,2,1,1,1,1,1,1,2}}, + {:'id-gost28147-cfb', {1,2,804,2,1,1,1,1,1,1,3}}, + {:'id-gost28147-wrap', {1,2,804,2,1,1,1,1,1,1,5}}, + {:'id-Dstu7624cfb-x256', {1,2,804,2,1,1,1,1,1,3,3,2}}, + {:'id-Dstu7624ofb-x256', {1,2,804,2,1,1,1,1,1,3,6,2}}, + {:'dstu4145WithGost34311-pb', {1,2,804,2,1,1,1,1,3,1,1}}, + {:'dstu4145WithGost34311onb', {1,2,804,2,1,1,1,1,3,1,2}}, + {:'gost34310WithGost34311', {1,2,804,2,1,1,1,1,3,2}}, + {:'dh-ua', {1,2,804,2,1,1,1,1,3,3}}, + {:'dhSinglePass-cofactorDH-gost34311kdf', {1,2,804,2,1,1,1,1,3,4}}, + {:'dhSinglePass-stdDH-gost34311kdf', {1,2,804,2,1,1,1,1,3,5}}, + {:dstu4145WithDstu7564, {1,2,804,2,1,1,1,1,3,6}}, + {:"dstu4145WithDstu7564-256", {1,2,804,2,1,1,1,1,3,6,1}}, + {:"dstu4145WithDstu7564-384", {1,2,804,2,1,1,1,1,3,6,2}}, + {:"dstu4145WithDstu7564-512", {1,2,804,2,1,1,1,1,3,6,3}}, + {:'id-ecPublicKey', {1,2,840,10045,2,1}}, {:secp192r1, {1,2,840,10045,3,1,1}}, {:secp256r1, {1,2,840,10045,3,1,7}}, diff --git a/lib/services/cmp.ex b/lib/services/cmp.ex index cb22b0d..c85bdf2 100644 --- a/lib/services/cmp.ex +++ b/lib/services/cmp.ex @@ -4,13 +4,13 @@ defmodule CA.CMP do def parseSubj(csr) do {:CertificationRequest, {:CertificationRequestInfo, v, subj, x, y}, b, c} = csr - {:CertificationRequest, {:CertificationRequestInfo, v, CA.CAdES.subj(subj), x, y}, b, c} + {:CertificationRequest, {:CertificationRequestInfo, v, CA.CRT.subj(subj), x, y}, b, c} end def convertOTPtoPKIX(cert) do {:Certificate,{:TBSCertificate,:v3,a,ai,rdn,v,rdn2,{p1,{p21,p22,_pki},p3},b,c,ext},ai,code} = :public_key.pkix_decode_cert(:public_key.pkix_encode(:OTPCertificate, cert, :otp), :plain) - {:Certificate,{:TBSCertificate,:v3,a,ai,CA.CAdES.unsubj(rdn),v,CA.CAdES.unsubj(rdn2), + {:Certificate,{:TBSCertificate,:v3,a,ai,CA.CRT.unsubj(rdn),v,CA.CRT.unsubj(rdn2), {p1,{p21,p22,{:namedCurve,{1,3,132,0,34}}},p3},b,c,ext},ai,code} end @@ -102,7 +102,7 @@ defmodule CA.CMP do {ca_key, ca} = CA.CSR.read_ca() subject = X509.CSR.subject(csr) true = X509.CSR.valid?(parseSubj(csr)) - cert = X509.Certificate.new(X509.CSR.public_key(csr), CA.CAdES.subj(subject), ca, ca_key, + cert = X509.Certificate.new(X509.CSR.public_key(csr), CA.CRT.subj(subject), ca, ca_key, extensions: [subject_alt_name: X509.Certificate.Extension.subject_alt_name(["synrc.com"]) ]) reply = CA."CertRepMessage"(response: diff --git a/lib/services/crt.ex b/lib/services/crt.ex index 0ae6532..c069bd9 100644 --- a/lib/services/crt.ex +++ b/lib/services/crt.ex @@ -11,16 +11,17 @@ defmodule CA.CRT do end def unsubj({:rdnSequence, attrs}) do - {:rdnSequence, :lists.flatmap(fn [{t,oid,x}] -> + {:rdnSequence, :lists.flatmap(fn [{t,oid,x}] when is_binary(x) -> case :asn1rt_nif.decode_ber_tlv(x) do {{12,a},_} -> [{t,oid,{:uTF8String,a}}] {{19,a},_} -> [{t,oid,:erlang.binary_to_list(a)}] - end end, attrs)} + end + _ -> [] end, attrs)} end def readSignature(name \\ "2.p7s") do {:ok, bin} = :file.read_file name - ber = parseSignData(bin) + ber = CA.CMS.parseSignData(bin) ber end @@ -56,9 +57,13 @@ defmodule CA.CRT do 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, :base64.encode(hd(pair(v,[])))} - def oid({2,5,29,15},[v]), do: {:keyUsage, CA.EST.decodeKeyUsage(<<3,2,v::binary>>)} + def oid({2,5,29,15},[v]), do: {:keyUsage, CA.EST.decodeKeyUsage(<<3,2,v::binary>>) } def oid({2,5,29,16},v), do: {:privateKeyUsagePeriod, v} - def oid({2,5,29,17},v), do: {:subjectAltName, v} + def oid({2,5,29,17},v), do: {:subjectAltName, :lists.map(fn x -> + case CA.ALG.lookup(:oid.decode(x)) do + false -> x + {alg,_} -> alg + end end, v)} def oid({2,5,29,37},v), do: {:extKeyUsage, mapOids(:lists.map(fn x -> :oid.decode(x) end, v)) } def oid({2,5,29,19},v), do: {:basicConstraints, v} def oid({2,5,29,31},v), do: {:cRLDistributionPoints, pair(v,[])} @@ -88,9 +93,11 @@ defmodule CA.CRT do def rdn({2, 5, 4, 3}), do: "cn" def rdn({2, 5, 4, 6}), do: "c" + def rdn({2, 5, 4, 7}), do: "l" def rdn({2, 5, 4, 10}), do: "o" def rdn({:rdnSequence, list}) do - Enum.join :lists.map(fn {_,oid,list} -> "#{rdn(oid)}=#{list}" end, list), "/" + Enum.join :lists.map(fn {_,oid,{_,list}} -> "#{rdn(oid)}=#{list}" + {_,oid,list} -> "#{rdn(oid)}=#{list}" end, list), "/" end def decodePointFromPublic(oid0,oid,publicKey) do @@ -113,24 +120,16 @@ defmodule CA.CRT do extensions = :lists.map(fn {:Extension,code,_x,b} -> oid(code, :lists.flatten(flat(code,:asn1rt_nif.decode_ber_tlv(b),[]))) end, exts) + :io.format '~p', [oid] [ version: ver, signatureAlgorithm: :erlang.element(1,CA.ALG.lookup(alg)), subject: rdn(unsubj(issuee)), issuer: rdn(unsubj(issuer)), serial: :base64.encode(CA.EST.integer(serial)), validity: [from: nb, to: na], - publicKey: decodePointFromPublic(oid, CA.EST.decodeObjectIdentifier(oid2),publicKey), +# publicKey: decodePointFromPublic(oid, CA.EST.decodeObjectIdentifier(oid2),publicKey), extensions: extensions ] end - def parseSignData(bin) do - {_, {:ContentInfo, oid, ci}} = :KEP.decode(:ContentInfo, bin) - {:ok, {:SignedData, a, alg, x, c, x1, si}} = :KEP.decode(:SignedData, ci) - {:SignedData, a, alg, x, parseSignDataCert({alg,oid,x,c,x1,si}), x1, si} - end - - def parseSignDataCert({_,_,_,:asn1_NOVALUE,_,_}), do: [] - def parseSignDataCert({_,_,_,certs,_,si}), do: :lists.map(fn cert -> parseCert(cert, si) end, certs) - end diff --git a/lib/signing/ecdsa.ex b/lib/signing/ecdsa.ex index 0ef6e38..d3f34e2 100644 --- a/lib/signing/ecdsa.ex +++ b/lib/signing/ecdsa.ex @@ -4,12 +4,6 @@ defmodule CA.ECDSA do require CA.Jacobian @moduledoc "CA/ECDSA ECC Signature (SYNRC)." - def decode_integer(bin) do - len = :erlang.size(bin) - <> = bin - int - end - def sign(message, privateKey, options) do %{hashfunc: hashfunc} = Enum.into(options, %{hashfunc: :sha256}) number = :crypto.hash(hashfunc, message) |> numberFromString() diff --git a/src/oid.erl b/src/oid.erl new file mode 100644 index 0000000..5d1a2f4 --- /dev/null +++ b/src/oid.erl @@ -0,0 +1,33 @@ +-module(oid). +-export([decode/1, hex/1, unhex/1]). + +digit(X) when X >= 0 andalso X =< 9 -> X + 48; +digit(X) when X >= 10 andalso X =< 15 -> X + 87. +hex(Bin) -> << << (digit(A1)),(digit(A2)) >> || <> <= Bin >>. +unhex(Hex) -> << << (erlang:list_to_integer([H1,H2], 16)) >> || <> <= Hex >>. + +match_tags({T, V}, [T]) -> V; +match_tags({T, V}, [T | Tt]) -> match_tags(V, Tt); +match_tags([{T, V}], [T | Tt]) -> match_tags(V, Tt); +match_tags([{T, _V} | _] = Vlist, [T]) -> Vlist; +match_tags(Tlv, []) -> Tlv; +match_tags({Tag, _V} = Tlv, [T | _Tt]) -> {error, {asn1, {wrong_tag, {{expected, T}, {got, Tag, Tlv}}}}}. + +dec_subidentifiers(<<>>, _Av, Al) -> lists:reverse(Al); +dec_subidentifiers(<<1:1,H:7,T/binary>>, Av, Al) -> dec_subidentifiers(T, Av bsl 7 + H, Al); +dec_subidentifiers(<>, Av, Al) -> dec_subidentifiers(T, 0, [Av bsl 7 + H | Al]). + +decode(Tlv) -> + Val = match_tags(Tlv, []), + [AddedObjVal | ObjVals] = dec_subidentifiers(Val, 0, []), + {Val1, Val2} = + if + AddedObjVal < 40 -> + {0, AddedObjVal}; + AddedObjVal < 80 -> + {1, AddedObjVal - 40}; + true -> + {2, AddedObjVal - 80} + end, + list_to_tuple([Val1, Val2 | ObjVals]). + \ No newline at end of file