JSValue js_generate_self_signed_cert()

in src/governance/ccf-app/cpp/app/js_extensions.cpp [73:161]


  JSValue js_generate_self_signed_cert(
    JSContext* ctx, JSValueConst, int argc, JSValueConst* argv)
  {
    if (argc != 5 && argc != 6)
      return JS_ThrowTypeError(
        ctx, "Passed %d arguments, but expected 5 or 6", argc);

    ccf::js::core::Context& jsctx =
      *(ccf::js::core::Context*)JS_GetContextOpaque(ctx);

    auto priv_key = jsctx.to_str(argv[0]);
    if (!priv_key)
    {
      return ccf::js::core::constants::Exception;
    }

    auto subject_name = jsctx.to_str(argv[1]);
    if (!subject_name)
    {
      return ccf::js::core::constants::Exception;
    }

    std::vector<std::string> subject_alt_names;
    bool allow_empty = true;
    JSValue rv =
      extract_string_array(jsctx, argv[2], subject_alt_names, allow_empty);
    if (!JS_IsUndefined(rv))
    {
      return JS_ThrowTypeError(ctx, "3rd argument must be a string array");
    }

    auto sans = ccf::crypto::sans_from_string_list(subject_alt_names);

    int32_t validity_period_days;
    if (JS_ToInt32(ctx, &validity_period_days, argv[3]) < 0)
    {
      return ccf::js::core::constants::Exception;
    }

    const auto v = argv[4];
    if (!JS_IsBool(v))
    {
      return JS_ThrowTypeError(ctx, "5th argument must be a boolean");
    }
    auto ca = JS_ToBool(ctx, v);

    std::optional<int> ca_path_len_constraint;
    if (argc == 6)
    {
      int32_t value;
      if (JS_ToInt32(ctx, &value, argv[5]) < 0)
      {
        return ccf::js::core::constants::Exception;
      }
      ca_path_len_constraint = value;
    }

    try
    {
      auto kp = cleanroom::crypto::make_key_pair(priv_key.value());
      OPENSSL_cleanse(priv_key.value().data(), priv_key.value().size());
      using namespace std::literals;
      // valid_from starts a day before the current time so validity period is
      // adjusted accordingly by increasing the input validity_period_days by 1.
      auto valid_from =
        ccf::ds::to_x509_time_string(std::chrono::system_clock::now() - 24h);
      ccf::crypto::Pem cert_pem = cleanroom::crypto::create_self_signed_cert(
        kp,
        subject_name.value(),
        sans,
        valid_from,
        validity_period_days + 1,
        ca,
        ca_path_len_constraint);

      auto r = jsctx.new_obj();
      JS_CHECK_EXC(r);
      auto cert = jsctx.new_string_len((char*)cert_pem.data(), cert_pem.size());
      JS_CHECK_EXC(cert);
      JS_CHECK_SET(r.set("cert", std::move(cert)));

      return r.take();
    }
    catch (const std::exception& exc)
    {
      return JS_ThrowInternalError(
        ctx, "Failed to generate self signed cert: %s", exc.what());
    }
  }