68 constexpr static size_t kMaxSHABlocks = SHABlocks;
69 using Field =
typename EC::Field;
71 using Nat =
typename Field::N;
80 uint8_t preimage_[64 * kMaxSHABlocks];
85 size_t payload_ind_, payload_len_;
86 std::vector<size_t> attr_ind_;
91 size_t payload_len, payload_ind;
96 bool parse_jws(std::string jwt,
Jws& jws) {
97 size_t dot = jwt.find_first_of(
'.');
98 if (dot == std::string::npos) {
99 log(ERROR,
"JWT is not well-formed");
102 size_t dot2 = jwt.find_first_of(
'.', dot + 1);
103 if (dot2 == std::string::npos) {
104 log(ERROR,
"JWT is not in the format of header.payload.signature");
107 auto hdr = jwt.substr(0, dot);
108 auto pld = jwt.substr(dot + 1, dot2 - dot - 1);
109 auto sig = jwt.substr(dot2 + 1);
110 jws.msg = jwt.substr(0, dot2);
112 jws.payload_ind = dot + 1;
113 jws.payload_len = pld.size();
115 uint8_t hash[kSHA256DigestSize];
117 sha.Update((
const uint8_t*)jws.msg.data(), dot2);
118 sha.DigestData(hash);
119 jws.ne = nat_from_be(hash);
121 std::vector<uint8_t> sigb;
122 sigb.reserve(ec_.f_.kBytes * 2);
123 if (!base64_decode_url(sig, sigb) || sigb.size() < ec_.f_.kBytes * 2) {
124 log(ERROR,
"signature is not in the format of base64url");
127 jws.nr = nat_from_be(&sigb[0]);
128 jws.ns = nat_from_be(&sigb[ec_.f_.kBytes]);
130 jws.e = ec_.f_.to_montgomery(jws.ne);
131 jws.r = ec_.f_.to_montgomery(jws.nr);
132 jws.s = ec_.f_.to_montgomery(jws.ns);
137 explicit JWTWitness(
const EC& ec,
const ScalarField& Fn)
138 : ec_(ec), sig_(Fn, ec), kb_sig_(Fn, ec) {}
140 void fill_witness(DenseFiller<Field>& filler)
const {
141 filler.push_back(e_);
142 filler.push_back(dpkx_);
143 filler.push_back(dpky_);
144 sig_.fill_witness(filler);
145 kb_sig_.fill_witness(filler);
148 for (
size_t i = 0; i < 64 * kMaxSHABlocks; ++i) {
149 filler.push_back(preimage_[i], 8, ec_.f_);
152 for (
size_t i = 0; i < 256; ++i) {
153 filler.push_back(e_bits_[i], 1, ec_.f_);
156 for (
size_t j = 0; j < kMaxSHABlocks; ++j) {
157 fill_sha(filler, sha_bw_[j]);
160 filler.push_back(numb_, 8, ec_.f_);
162 for (
size_t i = 0; i < na_; ++i) {
163 filler.push_back(attr_ind_[i], kJWTIndexBits, ec_.f_);
166 filler.push_back(payload_ind_, kJWTIndexBits, ec_.f_);
167 filler.push_back(payload_len_, kJWTIndexBits, ec_.f_);
170 void fill_sha(DenseFiller<Field>& filler,
171 const FlatSHA256Witness::BlockWitness& bw)
const {
172 BitPluckerEncoder<Field, kSHAJWTPluckerBits> BPENC(ec_.f_);
173 for (
size_t k = 0; k < 48; ++k) {
174 filler.push_back(BPENC.mkpacked_v32(bw.outw[k]));
176 for (
size_t k = 0; k < 64; ++k) {
177 filler.push_back(BPENC.mkpacked_v32(bw.oute[k]));
178 filler.push_back(BPENC.mkpacked_v32(bw.outa[k]));
180 for (
size_t k = 0; k < 8; ++k) {
181 filler.push_back(BPENC.mkpacked_v32(bw.h1[k]));
187 Nat nat_from_u32(
const uint32_t be[])
const {
188 uint8_t tmp[Nat::kBytes];
189 const size_t top = Nat::kBytes / 4;
190 for (
size_t i = 0; i < Nat::kBytes; ++i) {
191 tmp[i] = (be[top - i / 4 - 1] >> ((i % 4) * 8)) & 0xff;
193 return Nat::of_bytes(tmp);
198 Nat nat_from_be(
const uint8_t be[]) {
199 uint8_t tmp[Nat::kBytes];
201 for (
size_t i = 0; i < Nat::kBytes; ++i) {
202 tmp[i] = be[Nat::kBytes - i - 1];
204 return Nat::of_bytes(tmp);
207 bool compute_witness(std::string jwt, Elt pkX, Elt pkY,
208 std::vector<OpenedAttribute> attrs) {
209 size_t tilde = jwt.find_first_of(
'~');
210 if (tilde == std::string::npos) {
211 log(ERROR,
"JWT is not in the format of header.payload.signature~kb");
214 auto id = jwt.substr(0, tilde);
215 auto kb = jwt.substr(tilde + 1);
217 if (!parse_jws(
id, id_jws)) {
221 if (id_jws.msg.size() > kMaxSHABlocks * 64 - 9) {
222 log(INFO,
"JWT payload bytes is too large");
226 FlatSHA256Witness::transform_and_witness_message(
227 id_jws.msg.size(),
reinterpret_cast<const uint8_t*
>(id_jws.msg.data()),
228 kMaxSHABlocks, numb_, preimage_, sha_bw_);
231 payload_ind_ = id_jws.payload_ind;
232 payload_len_ = id_jws.payload_len;
233 if (!sig_.compute_witness(pkX, pkY, id_jws.ne, id_jws.nr, id_jws.ns)) {
234 log(ERROR,
"signature verification failed");
238 for (
size_t i = 0; i < 256; ++i) {
239 e_bits_[i] = id_jws.ne.bit(i);
244 std::vector<uint8_t> payload;
245 payload.reserve(id_jws.payload.size());
246 if (!base64_decode_url(id_jws.payload, payload)) {
247 log(ERROR,
"JWT payload is not in the format of base64url");
250 std::string str((
const char*)payload.data(), payload.size());
251 for (
size_t i = 0; i < na_; ++i) {
253 "\"" + std::string((
const char*)attrs[i].
id, attrs[i].id_len) +
255 std::string((
const char*)attrs[i].value, attrs[i].value_len) +
"\"";
256 size_t ind = str.find(idm, 0);
257 if (ind == std::string::npos) {
258 log(ERROR,
"Could not find attribute %s", idm.c_str());
261 attr_ind_.push_back(ind);
265 std::string cnf_prefix =
266 "\"cnf\":{\"jwk\":{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"";
267 size_t x_ind = str.find(cnf_prefix.data(), 0, cnf_prefix.size());
268 if (x_ind == std::string::npos) {
269 log(ERROR,
"Could not find device public key in payload");
272 size_t y_ind = str.find(
"\",\"y\":\"", x_ind + cnf_prefix.size());
273 if (y_ind == std::string::npos) {
274 log(ERROR,
"Could not find device public key in payload");
277 std::string x = str.substr(x_ind + cnf_prefix.size(), 43);
278 std::string y = str.substr(y_ind + 7, 43);
279 std::vector<uint8_t> dpkx, dpky;
280 dpkx.reserve(65); dpky.reserve(65);
281 if (!base64_decode_url(x, dpkx)) {
282 log(ERROR,
"CNF:dpkx payload is not in the format of base64url");
285 if (!base64_decode_url(y, dpky)) {
286 log(ERROR,
"CNF:dpky payload is not in the format of base64url");
289 Nat nx = nat_from_be(dpkx.data());
290 Nat ny = nat_from_be(dpky.data());
291 dpkx_ = ec_.f_.to_montgomery(nx);
292 dpky_ = ec_.f_.to_montgomery(ny);
296 log(ERROR,
"kb portion is missing");
300 if (!parse_jws(kb, kb_jws)) {
301 log(ERROR,
"kb jws parsing failed");
304 if (!kb_sig_.compute_witness(dpkx_, dpky_, kb_jws.ne, kb_jws.nr,
306 log(ERROR,
"kb signature verification failed");