mad_ca.erl 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. -module(mad_ca).
  2. -include_lib("public_key/include/public_key.hrl").
  3. -compile(export_all).
  4. host() -> "ca.n2o.dev:8046".
  5. cat(X) -> lists:concat(X).
  6. replace(S,A,B) -> re:replace(S,A,B,[global,{return,binary}]).
  7. u(X) -> string:to_upper(X).
  8. root(Crypto) -> {cat(["cert/",Crypto,"/"]),"synrc.cnf"}.
  9. rsa(X) -> cmd("rsa",X).
  10. ecc(X) -> cmd("ecc",X).
  11. cmd(C,[]) -> boot(C), {ok,C};
  12. cmd(C,["ca"]) -> boot(C), up(C), {ok,C};
  13. cmd(C,[T|N]) -> boot(C), enroll(C,T,N), {ok,C};
  14. cmd(C,_) -> boot(C), {ok,C}.
  15. boot(Crypto) ->
  16. {Dir,CNF} = root(Crypto),
  17. case file:read_file_info(Dir++CNF) of
  18. {ok,_} -> skip;
  19. {error,_} -> {Dir,CNF} = root(Crypto), filelib:ensure_dir(Dir),
  20. file:write_file(Dir++CNF,replace(replace(cnf(),"PATH",mad_utils:cwd()),"CRYPTO",Crypto)),
  21. up(Crypto) end, {ok,Crypto}.
  22. up(Crypto) ->
  23. application:start(inets),
  24. URI = cat(["http://",host(),"/up/",Crypto]),
  25. {ok,{{"HTTP/1.1",200,"OK"},_,Cert}} = httpc:request(post,{URI,[],[],<<"">>},[],[]),
  26. PEM = list_to_binary(Cert),
  27. ok = file:write_file(cat(["cert/",Crypto,"/caroot.pem"]),PEM),
  28. dump(PEM,"CA").
  29. enroll(Crypto,Type,Name) when (Type == "server" orelse Type == "client" orelse Type == "ocsp")
  30. andalso (Crypto == "rsa" orelse Crypto == "ecc") ->
  31. Pass = application:get_env(ca,passin,"pass:0"),
  32. application:start(inets),
  33. Y = string:join(Name," "),
  34. ok = key(Crypto,Pass,Y),
  35. {ok, F} = file:read_file(cat(["cert/",Crypto,"/",Y,".csr"])),
  36. URI = cat(["http://",host(),"/enroll/",Crypto,"/",Type]),
  37. {ok,{{"HTTP/1.1",200,"OK"},_,Cert}} = httpc:request(post,{URI,[],"multipart/form-data",F},[],[]),
  38. PEM = list_to_binary(Cert),
  39. ok = file:write_file(cat(["cert/",Crypto,"/",Y,".pem"]),PEM),
  40. dump(PEM,Y).
  41. dump(PEM,Y) ->
  42. {_,{_,D,_}} = lists:keysearch('Certificate',1,public_key:pem_decode(PEM)),
  43. OTPCert = public_key:pkix_decode_cert(D,otp),
  44. PKIInfo = OTPCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subjectPublicKeyInfo,
  45. io:format("CERT: ~s KEY: ~p~n",[Y,PKIInfo]).
  46. key("rsa",_,X) ->
  47. {done,0,_} = sh:run("openssl genrsa -out \"cert/rsa/"++ X ++ ".key\" 2048"),
  48. {done,0,_} = sh:run("openssl req -new -days 365 -key \"cert/rsa/"++ X ++".key\" -out \"cert/rsa/"++ X ++".csr\" "
  49. " -subj \"/C=UA/ST=Kyiv/O=SYNRC/CN="++ X ++ "\""), ok;
  50. key("ecc",Pass,X) ->
  51. Pass = application:get_env(ca,passin,"pass:0"),
  52. {done,0,_} = sh:run("openssl ecparam -name secp384r1 -out \"cert/ecc/"++X++".ecp\""),
  53. {done,0,_} = sh:run("cp \"cert/ecc/"++X++".ecp\" key"),
  54. {done,0,_} = sh:run("openssl req -config cert/ecc/synrc.cnf -passout " ++ Pass ++
  55. " -new -newkey ec:key -keyout \"cert/ecc/"++X++".key.enc\" -out \"cert/ecc/"++X++".csr\""
  56. " -subj \"/C=UA/ST=Kyiv/O=SYNRC/CN="++X++"\""),
  57. {done,0,_} = sh:run("rm key"),
  58. {done,0,_} = sh:run("openssl ec -in \"cert/ecc/"++X++".key.enc\" -out \"cert/ecc/"++X++".key\" -passin "++Pass),
  59. ok.
  60. cnf() ->
  61. mad_repl:load(),
  62. try lists:flatten(
  63. [case string:str(File,"priv/cnf") of 1 -> Bin; _ -> []
  64. end || {File,Bin} <- ets:tab2list(filesystem), is_list(File)])
  65. catch _:_ -> [] end.