anchor.diff:  
   -include("ns_common.hrl").
   
  +-include_lib("public_key/include/public_key.hrl").
  +
   -export([cluster_cert_and_pkey_pem/0,
            do_generate_cert_and_pkey/2,
            validate_cert/1,
  -         generate_and_set_cert_and_pkey/0]).
  -
  -cluster_cert_and_pkey_pem() ->
  +         generate_and_set_cert_and_pkey/0,
  +         cluster_ca/0,
  +         set_cluster_ca/1]).
  +
  +cluster_ca() ->
       case ns_config:search(cert_and_pkey) of
  -        {value, Pair} ->
  -            Pair;
  +        {value, Tuple} ->
  +            Tuple;
           false ->
               Pair = generate_cert_and_pkey(),
               RV = ns_config:run_txn(
  
positive.code:                 _ ->
                      Pair
              end
      end.
  
  generate_and_set_cert_and_pkey() ->
  
negative.code:             erlang:exit({bad_cert_or_pkey, BadResults})
      end,
      {Cert, PKey}.
  
  attribute_string(?'id-at-countryName') ->
      "C";
  attribute_string(?'id-at-stateOrProvinceName') ->
      "ST";
  attribute_string(?'id-at-localityName') ->
      "L";
  attribute_string(?'id-at-organizationName') ->
      "O";
  attribute_string(?'id-at-commonName') ->
      "CN";
  attribute_string(_) ->
      undefined.
  
  format_attribute([#'AttributeTypeAndValue'{type = Type,
                                             value = Value}], Acc) ->
      case attribute_string(Type) of
          undefined ->
              Acc;
          Str ->
              [[Str, "=", format_value(Value)] | Acc]
      end.
  
  format_value({_, Value}) when is_list(Value) ->
      Value;
  format_value(Value) when is_list(Value) ->
      Value;
  format_value(Value) ->
      io_lib:format("~p", [Value]).
  
  format_name({rdnSequence, STVList}) ->
      Attributes = lists:foldl(fun format_attribute/2, [], STVList),
      lists:flatten(string:join(lists:reverse(Attributes), ", ")).
  
  convert_date(Year, Rest) ->
      {ok, [Month, Day, Hour, Min, Sec], "Z"} = io_lib:fread("~2d~2d~2d~2d~2d", Rest),
      calendar:datetime_to_gregorian_seconds({{Year, Month, Day}, {Hour, Min, Sec}}).
  
  convert_date({utcTime, [Y1, Y2 | Rest]}) ->
      Year = list_to_integer([Y1, Y2]) + 2000,
      convert_date(Year, Rest);
  convert_date({generalTime, [Y1, Y2, Y3, Y4 | Rest]}) ->
      Year = list_to_integer([Y1, Y2, Y3, Y4]),
      convert_date(Year, Rest).
  
  get_info(DerCert) ->
      Decoded = public_key:pkix_decode_cert(DerCert, otp),
      TBSCert = Decoded#'OTPCertificate'.tbsCertificate,
      Subject = format_name(TBSCert#'OTPTBSCertificate'.subject),
  
      Validity = TBSCert#'OTPTBSCertificate'.validity,
      NotBefore = convert_date(Validity#'Validity'.notBefore),
      NotAfter = convert_date(Validity#'Validity'.notAfter),
      {Subject, NotBefore, NotAfter}.
  
  parse_cluster_ca(CA) ->
      case validate_cert(CA) of
          {ok, []} ->
              {error, malformed_cert, CA};
          {ok, [{'Certificate', RootCertDer, not_encrypted}]} ->
              Info = {Subject, NotBefore, NotAfter} =
                  try
                      get_info(RootCertDer)
                  catch T:E ->
                          {error, malformed_cert, {T,E,erlang:get_stacktrace()}}
                  end,
              case Info of
                  {error, malformed_cert, _} = E1 ->
                      E1;
                  _ ->
                      UTC = calendar:datetime_to_gregorian_seconds(
                              calendar:universal_time()),
                      case NotBefore > UTC orelse NotAfter < UTC of
                          true ->
                              {error, not_valid_at_this_time, [{now, UTC}, Info]};
                          false ->
                              {ok, [{pem, CA},
                                    {subject, Subject},
                                    {expires, NotAfter}]}
                      end
              end;
          {ok, OtherList} ->
              {error, too_many_entries, OtherList};
          Error ->
              Error
      end.
  
  set_cluster_ca(CA) ->
      case parse_cluster_ca(CA) of
          {ok, Props} ->
              RV = ns_config:run_txn(
                     fun (Config, SetFn) ->
                             {GeneratedCert, GeneratedKey} =
                                 case ns_config:search(Config, cert_and_pkey) of
                                     {value, {_, _} = Pair} ->
                                         Pair;
                                     {value, {_, GeneratedCert1, GeneratedKey1}} ->
                                         {GeneratedCert1, GeneratedKey1};
                                     false ->
                                         generate_cert_and_pkey()
                                 end,
                             {commit, SetFn(cert_and_pkey,
                                            {Props, GeneratedCert, GeneratedKey}, Config)}
                     end),
              case RV of
                  {commit, _} ->
                      ok;
                  retry_needed ->
                      erlang:error(exceeded_retries)
              end;
          {error, Error, _} = Err ->
              ?log_error("Certificate authority validation failed with ~p", [Err]),
              {error, Error}
      end.
  