CCF
Loading...
Searching...
No Matches
js_policy.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3
4#pragma once
5
7#include "ccf/ds/hex.h"
10#include "js/checks.h"
11#include "node/cose_common.h"
12
13#include <fmt/format.h>
14#include <optional>
15#include <string>
16
17namespace ccf::policy
18{
19 static ccf::js::core::JSWrappedValue protected_header_to_js_val(
21 {
22 auto obj = ctx.new_obj();
23
24 JS_CHECK_OR_THROW(obj.set_int64("alg", phdr.alg));
25
26 if (phdr.cty.has_value())
27 {
28 if (std::holds_alternative<int64_t>(phdr.cty.value()))
29 {
31 obj.set_int64("cty", std::get<int64_t>(phdr.cty.value())));
32 }
33 else if (std::holds_alternative<std::string>(phdr.cty.value()))
34 {
35 JS_CHECK_OR_THROW(obj.set(
36 "cty", ctx.new_string(std::get<std::string>(phdr.cty.value()))));
37 }
38 }
39
40 auto x5_array = ctx.new_array();
41 size_t i = 0;
42 for (const auto& der_cert : phdr.x5chain)
43 {
44 auto pem = ccf::crypto::cert_der_to_pem(der_cert);
45 JS_CHECK_OR_THROW(x5_array.set_at_index(i++, ctx.new_string(pem.str())));
46 }
47 JS_CHECK_OR_THROW(obj.set("x5chain", std::move(x5_array)));
48
49 auto cwt = ctx.new_obj();
50 if (!phdr.cwt.iss.empty())
51 {
52 JS_CHECK_OR_THROW(cwt.set("iss", ctx.new_string(phdr.cwt.iss)));
53 }
54 if (!phdr.cwt.sub.empty())
55 {
56 JS_CHECK_OR_THROW(cwt.set("sub", ctx.new_string(phdr.cwt.sub)));
57 }
58 if (phdr.cwt.iat.has_value())
59 {
60 JS_CHECK_OR_THROW(cwt.set_int64("iat", phdr.cwt.iat.value()));
61 }
62 if (phdr.cwt.svn.has_value())
63 {
64 JS_CHECK_OR_THROW(cwt.set_int64("svn", phdr.cwt.svn.value()));
65 }
66 JS_CHECK_OR_THROW(obj.set("cwt", std::move(cwt)));
67
68 return obj;
69 }
70
72 {
74 std::vector<cose::Leaf> leaves;
75 };
76
77 static ccf::js::core::JSWrappedValue receipt_to_js_val(
78 ccf::js::core::Context& ctx, const ReceiptPolicyInput& receipt)
79 {
80 auto obj = ctx.new_obj();
81
82 JS_CHECK_OR_THROW(obj.set_int64("alg", receipt.phdr.alg));
83 JS_CHECK_OR_THROW(obj.set_int64("vds", receipt.phdr.vds));
84
85 if (!receipt.phdr.kid.empty())
86 {
87 auto kid_str =
88 std::string(receipt.phdr.kid.begin(), receipt.phdr.kid.end());
89 JS_CHECK_OR_THROW(obj.set("kid", ctx.new_string(kid_str)));
90 }
91
92 auto cwt = ctx.new_obj();
93
94 JS_CHECK_OR_THROW(cwt.set("iss", ctx.new_string(receipt.phdr.cwt.iss)));
95 JS_CHECK_OR_THROW(cwt.set("sub", ctx.new_string(receipt.phdr.cwt.sub)));
96
97 if (receipt.phdr.cwt.iat.has_value())
98 {
99 JS_CHECK_OR_THROW(cwt.set_int64("iat", receipt.phdr.cwt.iat.value()));
100 }
101 JS_CHECK_OR_THROW(obj.set("cwt", std::move(cwt)));
102
103 auto ccf_obj = ctx.new_obj();
104 if (!receipt.phdr.ccf.txid.empty())
105 {
107 ccf_obj.set("txid", ctx.new_string(receipt.phdr.ccf.txid)));
108 }
109 JS_CHECK_OR_THROW(obj.set("ccf", std::move(ccf_obj)));
110
111 // Leaves: one per Merkle inclusion proof
112 auto leaves_arr = ctx.new_array();
113 for (size_t k = 0; k < receipt.leaves.size(); ++k)
114 {
115 const auto& leaf = receipt.leaves[k];
116 auto leaf_obj = ctx.new_obj();
117 if (!leaf.claims_digest.empty())
118 {
119 auto hex = ccf::ds::to_hex(leaf.claims_digest);
120 JS_CHECK_OR_THROW(leaf_obj.set("claims_digest", ctx.new_string(hex)));
121 }
122 if (!leaf.commit_evidence.empty())
123 {
124 JS_CHECK_OR_THROW(leaf_obj.set(
125 "commit_evidence", ctx.new_string(leaf.commit_evidence)));
126 }
127 if (!leaf.write_set_digest.empty())
128 {
129 auto hex = ccf::ds::to_hex(leaf.write_set_digest);
131 leaf_obj.set("write_set_digest", ctx.new_string(hex)));
132 }
133 JS_CHECK_OR_THROW(leaves_arr.set_at_index(k, std::move(leaf_obj)));
134 }
135 JS_CHECK_OR_THROW(obj.set("leaves", std::move(leaves_arr)));
136
137 return obj;
138 }
139
141 {
143 std::vector<ReceiptPolicyInput> receipts;
144 };
145
146 static std::optional<std::string> apply_node_join_policy(
147 const std::string& policy_script,
148 const std::vector<TransparentStatementPolicyInput>& statements)
149 {
151
153 try
154 {
155 apply_func = interpreter.get_exported_function(
156 policy_script, "apply", "node_join_policy");
157 }
158 catch (const std::exception& e)
159 {
160 return fmt::format("Invalid code update policy module: {}", e.what());
161 }
162
163 // Build JS array of transparent statements, each with phdr + receipts
164 auto ts_array = interpreter.new_array();
165 for (size_t i = 0; i < statements.size(); ++i)
166 {
167 auto ts_obj = interpreter.new_obj();
168
169 auto phdr_val =
170 protected_header_to_js_val(interpreter, statements[i].phdr);
171 JS_CHECK_OR_THROW(ts_obj.set("phdr", std::move(phdr_val)));
172
173 auto receipts_arr = interpreter.new_array();
174 for (size_t j = 0; j < statements[i].receipts.size(); ++j)
175 {
176 auto receipt_val =
177 receipt_to_js_val(interpreter, statements[i].receipts[j]);
178 JS_CHECK_OR_THROW(receipts_arr.set_at_index(j, std::move(receipt_val)));
179 }
180 JS_CHECK_OR_THROW(ts_obj.set("receipts", std::move(receipts_arr)));
181
182 JS_CHECK_OR_THROW(ts_array.set_at_index(i, std::move(ts_obj)));
183 }
184
185 const auto result = interpreter.call_with_rt_options(
186 apply_func,
187 {ts_array},
190
191 if (result.is_exception())
192 {
193 auto [reason, trace] = interpreter.error_message();
194 return fmt::format(
195 "Code update policy threw: {}\n{}",
196 reason,
197 trace.value_or("<no trace>"));
198 }
199
200 if (result.is_str())
201 {
202 // Policy returned a string => reject
203 return interpreter.to_str(result);
204 }
205
206 if (JS_IsBool(result.val) != 0 && result.is_true())
207 {
208 // Policy returned boolean true => accepted
209 return std::nullopt;
210 }
211
212 return fmt::format(
213 "Unexpected return value from code update policy: {}",
214 interpreter.to_str(result).value_or("<unknown>"));
215 }
216}
#define JS_CHECK_OR_THROW(val)
Definition checks.h:23
Definition context.h:44
JSWrappedValue get_exported_function(const std::string &code, const std::string &func, const std::string &path)
Definition context.cpp:248
JSWrappedValue new_obj() const
Definition context.cpp:325
std::optional< std::string > to_str(const JSWrappedValue &x) const
Definition context.cpp:522
std::pair< std::string, std::optional< std::string > > error_message()
Definition context.cpp:180
JSWrappedValue new_string(const std::string_view &str) const
Definition context.cpp:361
JSWrappedValue call_with_rt_options(const JSWrappedValue &f, const std::vector< JSWrappedValue > &argv, const std::optional< ccf::JSRuntimeOptions > &options, RuntimeLimitsPolicy policy)
Definition context.cpp:463
JSWrappedValue new_array() const
Definition context.cpp:335
ccf::crypto::Pem cert_der_to_pem(const std::vector< uint8_t > &der)
Definition verifier.cpp:33
Definition js_policy.h:18
Definition jsengine.h:12
std::string txid
Definition cose_common.h:167
Definition cose_common.h:171
CwtClaims cwt
Definition cose_common.h:174
CcfClaims ccf
Definition cose_common.h:175
std::vector< uint8_t > kid
Definition cose_common.h:173
int vds
Definition cose_common.h:176
int alg
Definition cose_common.h:172
std::optional< int64_t > svn
Definition cose_common.h:59
std::string sub
Definition cose_common.h:58
std::optional< int64_t > iat
Definition cose_common.h:56
std::string iss
Definition cose_common.h:57
Definition cose_common.h:63
std::vector< std::vector< uint8_t > > x5chain
Definition cose_common.h:66
CwtClaims cwt
Definition cose_common.h:67
std::optional< std::variant< int64_t, std::string > > cty
Definition cose_common.h:65
int64_t alg
Definition cose_common.h:64
Definition wrapped_value.h:13
Definition js_policy.h:72
cose::CcfCoseReceiptPhdr phdr
Definition js_policy.h:73
std::vector< cose::Leaf > leaves
Definition js_policy.h:74
std::vector< ReceiptPolicyInput > receipts
Definition js_policy.h:143
cose::Sign1ProtectedHeader phdr
Definition js_policy.h:142