tart_module.c (59865B)
1 /* 2 This file is part of GNU Taler 3 Copyright (C) 2022 Taler Systems SA 4 5 GNU Taler is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 17 #include "quickjs/cutils.h" 18 #include "quickjs/list.h" 19 #include "quickjs/quickjs-libc.h" 20 21 #include <sodium.h> 22 #include <mbedtls/hkdf.h> 23 #include <mbedtls/bignum.h> 24 #include <mbedtls/error.h> 25 26 #include <ctype.h> 27 #include <string.h> 28 #include <assert.h> 29 30 #include <arpa/inet.h> 31 32 #if defined(__APPLE__) 33 #include <sqlite3.h> 34 #else 35 #include "sqlite3/sqlite3.h" 36 #endif 37 38 static JSValue js_encode_utf8(JSContext *ctx, JSValueConst this_val, 39 int argc, JSValueConst *argv) 40 { 41 const char *str; 42 size_t len; 43 JSValue buf; 44 str = JS_ToCStringLen2(ctx, &len, argv[0], FALSE); 45 // FIXME: Don't copy buffer but pass destructor function 46 buf = JS_NewArrayBufferCopy(ctx, (const uint8_t*) str, len); 47 JS_FreeCString(ctx, str); 48 return buf; 49 } 50 51 static JSValue js_crash_for_debug(JSContext *ctx, JSValueConst this_val, 52 int argc, JSValueConst *argv) 53 { 54 abort(); 55 return JS_EXCEPTION; 56 } 57 58 static JSValue js_random_bytes(JSContext *ctx, JSValueConst this_val, 59 int argc, JSValueConst *argv) 60 { 61 uint32_t nbytes; 62 JSValue buf; 63 if (0 != JS_ToUint32(ctx, &nbytes, argv[0])) { 64 return JS_EXCEPTION; 65 } 66 { 67 uint8_t randbuf[nbytes]; 68 randombytes_buf(randbuf, nbytes); 69 buf = JS_NewArrayBufferCopy(ctx, randbuf, nbytes); 70 } 71 return buf; 72 } 73 74 /** 75 * Get the decoded value corresponding to a character according to Crockford 76 * Base32 encoding. 77 * 78 * @param a a character 79 * @return corresponding numeric value 80 */ 81 static unsigned int 82 getValue__ (unsigned char a) 83 { 84 unsigned int dec; 85 86 switch (a) 87 { 88 case 'O': 89 case 'o': 90 a = '0'; 91 break; 92 93 case 'i': 94 case 'I': 95 case 'l': 96 case 'L': 97 a = '1'; 98 break; 99 100 /* also consider U to be V */ 101 case 'u': 102 case 'U': 103 a = 'V'; 104 break; 105 106 default: 107 break; 108 } 109 if ((a >= '0') && (a <= '9')) 110 return a - '0'; 111 if ((a >= 'a') && (a <= 'z')) 112 a = toupper (a); 113 /* return (a - 'a' + 10); */ 114 dec = 0; 115 if ((a >= 'A') && (a <= 'Z')) 116 { 117 if ('I' < a) 118 dec++; 119 if ('L' < a) 120 dec++; 121 if ('O' < a) 122 dec++; 123 if ('U' < a) 124 dec++; 125 return(a - 'A' + 10 - dec); 126 } 127 return -1; 128 } 129 130 static JSValue js_talercrypto_encode_crock(JSContext *ctx, JSValue this_val, 131 int argc, JSValueConst *argv) 132 { 133 size_t size; 134 uint8_t *buf; 135 uint8_t *out = NULL; 136 size_t out_size; 137 // 32 characters for encoding 138 static char *encTable__ = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"; 139 unsigned int wpos; 140 unsigned int rpos; 141 unsigned int bits; 142 unsigned int vbit; 143 const unsigned char *udata; 144 JSValue ret_val; 145 146 ret_val = JS_UNDEFINED; 147 148 buf = JS_GetArrayBuffer(ctx, &size, argv[0]); 149 150 if (!buf) { 151 goto exception; 152 } 153 154 assert (size < SIZE_MAX / 8 - 4); 155 out_size = size * 8; 156 157 if (out_size % 5 > 0) 158 out_size += 5 - out_size % 5; 159 out_size /= 5; 160 161 out = malloc (out_size + 1); 162 memset (out, 0, out_size + 1); 163 if (!out) { 164 goto exception; 165 } 166 167 udata = buf; 168 if (out_size < (size * 8 + 4) / 5) { 169 goto exception; 170 } 171 vbit = 0; 172 wpos = 0; 173 rpos = 0; 174 bits = 0; 175 while ((rpos < size) || (vbit > 0)) 176 { 177 if ((rpos < size) && (vbit < 5)) 178 { 179 /* eat 8 more bits */ 180 bits = (bits << 8) | udata[rpos++]; 181 vbit += 8; 182 } 183 if (vbit < 5) 184 { 185 bits <<= (5 - vbit); /* zero-padding */ 186 assert (vbit == ((size * 8) % 5)); 187 vbit = 5; 188 } 189 if (wpos >= out_size) 190 { 191 goto exception; 192 } 193 out[wpos++] = encTable__[(bits >> (vbit - 5)) & 31]; 194 vbit -= 5; 195 } 196 assert (0 == vbit); 197 if (wpos < out_size) { 198 out[wpos] = '\0'; 199 } 200 201 ret_val = JS_NewString(ctx, (char *) out); 202 203 done: 204 if (NULL != out) { 205 free(out); 206 } 207 return ret_val; 208 exception: 209 ret_val = JS_EXCEPTION; 210 goto done; 211 } 212 213 static JSValue js_talercrypto_decode_crock(JSContext *ctx, JSValue this_val, 214 int argc, JSValueConst *argv) 215 { 216 size_t rpos; 217 size_t wpos; 218 unsigned int bits; 219 unsigned int vbit; 220 int ret; 221 int shift; 222 size_t enclen; 223 size_t encoded_len; 224 const char *enc; 225 JSValue ret_val = JS_UNDEFINED; 226 unsigned char *uout = NULL; 227 size_t out_size; 228 JSValue abuf; 229 230 enc = JS_ToCStringLen2(ctx, &enclen, argv[0], FALSE); 231 if (!enc) { 232 goto exception; 233 } 234 235 out_size = (enclen * 5) / 8; 236 encoded_len = out_size * 8; 237 uout = malloc(out_size); 238 assert (out_size < SIZE_MAX / 8); 239 wpos = out_size; 240 rpos = enclen; 241 if ((encoded_len % 5) > 0) 242 { 243 vbit = encoded_len % 5; /* padding! */ 244 shift = 5 - vbit; 245 bits = (ret = getValue__ (enc[--rpos])) >> shift; 246 } 247 else 248 { 249 vbit = 5; 250 shift = 0; 251 bits = (ret = getValue__ (enc[--rpos])); 252 } 253 if ((encoded_len + shift) / 5 != enclen) { 254 JS_ThrowTypeError(ctx, "wrong encoded length"); 255 goto exception; 256 } 257 258 if (-1 == ret) { 259 JS_ThrowTypeError(ctx, "invalid character in encoding"); 260 goto exception; 261 } 262 while (wpos > 0) 263 { 264 if (0 == rpos) 265 { 266 goto exception; 267 } 268 bits = ((ret = getValue__ (enc[--rpos])) << vbit) | bits; 269 if (-1 == ret) { 270 goto exception; 271 } 272 vbit += 5; 273 if (vbit >= 8) 274 { 275 uout[--wpos] = (unsigned char) bits; 276 bits >>= 8; 277 vbit -= 8; 278 } 279 } 280 if ((0 != rpos) || (0 != vbit)) { 281 JS_ThrowTypeError(ctx, "rpos or vbit not zero"); 282 goto exception; 283 } 284 abuf = JS_NewArrayBufferCopy(ctx, uout, out_size); 285 if (JS_IsException(abuf)) { 286 goto exception; 287 } 288 ret_val = JS_NewTypedArraySimple(ctx, abuf, 1); 289 done: 290 JS_FreeCString(ctx, enc); 291 if (uout) { 292 free(uout); 293 } 294 return ret_val; 295 exception: 296 ret_val = JS_EXCEPTION; 297 goto done; 298 } 299 300 uint8_t *expect_fixed_buffer(JSContext *ctx, 301 JSValue val, size_t len, 302 const char *msg) 303 { 304 uint8_t *buf; 305 size_t sz; 306 307 buf = JS_GetArrayBuffer(ctx, &sz, val); 308 if (!buf) { 309 return NULL; 310 } 311 if (sz != len) { 312 JS_ThrowTypeError(ctx, "invalid length for %s", msg); 313 return NULL; 314 } 315 return buf; 316 } 317 318 int 319 expect_mpi(JSContext *ctx, 320 JSValue val, 321 const char *msg, 322 mbedtls_mpi *ret_mpi) 323 { 324 uint8_t *buf; 325 size_t sz; 326 327 buf = JS_GetArrayBuffer(ctx, &sz, val); 328 if (!buf) { 329 return -1; 330 } 331 if (0 != mbedtls_mpi_read_binary(ret_mpi, buf, sz)) { 332 return -1; 333 } 334 return 0; 335 } 336 337 #define CHECK(x) do { if (!(x)) { abort(); } } while (0) 338 339 typedef struct { 340 mbedtls_mpi N; 341 mbedtls_mpi e; 342 } RsaPub; 343 344 typedef uint8_t BlindingKeySecret[32]; 345 typedef uint8_t HashCode[64]; 346 347 int 348 rsa_public_key_decode(RsaPub *pkey, uint8_t *inbuf, size_t inbuf_len) 349 { 350 size_t sz; 351 uint8_t *p; /* read pointer */ 352 size_t mod_len; 353 size_t exp_len; 354 int ret; 355 356 CHECK(NULL != pkey); 357 if (inbuf_len < 4) { 358 ret = -1; 359 goto cleanup; 360 } 361 p = inbuf; 362 mod_len = ntohs(*((uint16_t *) p)); 363 p += sizeof(uint16_t); 364 exp_len = ntohs(*((uint16_t *) p)); 365 sz = 4 + mod_len + exp_len; 366 if (sz != inbuf_len) { 367 ret = -1; 368 goto cleanup; 369 } 370 p += sizeof(uint16_t); 371 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pkey->N, p, mod_len)); 372 p += mod_len; 373 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pkey->e, p, exp_len)); 374 375 cleanup: 376 if (ret != 0) { 377 mbedtls_mpi_free(&pkey->N); 378 mbedtls_mpi_free(&pkey->e); 379 } 380 return ret; 381 } 382 383 int 384 expect_rsa_pub(JSContext *ctx, 385 JSValue val, 386 const char *msg, 387 RsaPub *ret_rsa_pub) 388 { 389 uint8_t *rsa_enc; 390 size_t rsa_enc_len; 391 int ret = -1; 392 393 rsa_enc = JS_GetArrayBuffer(ctx, &rsa_enc_len, val); 394 if (!rsa_enc) { 395 goto cleanup; 396 } 397 if (0 != rsa_public_key_decode(ret_rsa_pub, rsa_enc, rsa_enc_len)) { 398 JS_ThrowTypeError(ctx, "rsa pubkey"); 399 goto cleanup; 400 } 401 ret = 0; 402 cleanup: 403 return ret; 404 } 405 406 #define REQUIRE(cond, _label) do { if (!(cond)) { goto _label; } } while (0) 407 408 409 static JSValue make_js_ta_copy(JSContext *ctx, uint8_t *data, size_t size) 410 { 411 JSValue array_buf; 412 413 array_buf = JS_NewArrayBufferCopy(ctx, data, size); 414 if (JS_IsException(array_buf)) { 415 return JS_EXCEPTION; 416 } 417 return JS_NewTypedArraySimple(ctx, array_buf, 1); 418 } 419 420 /** 421 * Make a JS typed array from an mbedtls MPI. 422 */ 423 static JSValue make_js_ta_mpi(JSContext *ctx, const mbedtls_mpi *v) 424 { 425 JSValue array_buf; 426 size_t sz; 427 uint8_t *buf = NULL; 428 JSValue ret_val; 429 430 sz = mbedtls_mpi_size(v); 431 buf = malloc(sz); 432 if (!buf) { 433 ret_val = JS_EXCEPTION; 434 goto cleanup; 435 } 436 437 if (0 != mbedtls_mpi_write_binary(v, buf, sz)) { 438 ret_val = JS_EXCEPTION; 439 goto cleanup; 440 } 441 442 // FIXME(#perf): Don't copy 443 array_buf = JS_NewArrayBufferCopy(ctx, buf, sz); 444 if (JS_IsException(array_buf)) { 445 ret_val = JS_EXCEPTION; 446 goto cleanup; 447 } 448 ret_val = JS_NewTypedArraySimple(ctx, array_buf, 1); 449 cleanup: 450 if (buf) { 451 free(buf); 452 } 453 return ret_val; 454 } 455 456 static JSValue js_talercrypto_hash(JSContext *ctx, JSValue this_val, 457 int argc, JSValueConst *argv) 458 { 459 size_t size; 460 uint8_t *buf; 461 unsigned char h[crypto_hash_BYTES]; 462 463 buf = JS_GetArrayBuffer(ctx, &size, argv[0]); 464 if (!buf) { 465 return JS_EXCEPTION; 466 } 467 crypto_hash_sha512(h, buf, size); 468 469 return make_js_ta_copy(ctx, h, crypto_hash_BYTES); 470 } 471 472 static JSValue js_talercrypto_hash_argon2id(JSContext *ctx, JSValue this_val, 473 int argc, JSValueConst *argv) 474 { 475 size_t pw_len; 476 size_t salt_len; 477 uint32_t iters; 478 uint32_t mem_size; 479 uint32_t hash_len; 480 uint8_t *pw; 481 uint8_t *salt; 482 uint8_t *hash = NULL; 483 484 JSValue ret_val; 485 486 // password: Uint8Array 487 pw = JS_GetArrayBuffer(ctx, &pw_len, argv[0]); 488 if (!pw) { 489 goto exception; 490 } 491 492 // salt: Uint8Array 493 salt = JS_GetArrayBuffer(ctx, &salt_len, argv[1]); 494 if (!salt) { 495 goto exception; 496 } 497 if (salt_len != crypto_pwhash_SALTBYTES) { 498 JS_ThrowTypeError(ctx, "invalid salt size"); 499 goto exception; 500 } 501 502 // iterations: number 503 if (0 != JS_ToUint32(ctx, &iters, argv[2])) { 504 goto exception; 505 } 506 507 // memorySize: number (kibibytes) 508 if (0 != JS_ToUint32(ctx, &mem_size, argv[3])) { 509 goto exception; 510 } 511 512 // hashLength: number 513 if (0 != JS_ToUint32(ctx, &hash_len, argv[4])) { 514 goto exception; 515 } 516 517 // Check for overflow when converting memory size to bytes 518 if (((unsigned long long)mem_size * 1024) > UINT32_MAX) { 519 JS_ThrowTypeError(ctx, "mem_size too large"); 520 goto exception; 521 } 522 523 hash = malloc(hash_len); 524 if (NULL == hash) { 525 goto exception; 526 } 527 528 if (crypto_pwhash(hash, 529 hash_len, 530 (const char*) pw, 531 pw_len, 532 salt, 533 iters, 534 mem_size * 1024, 535 crypto_pwhash_ALG_ARGON2ID13) != 0) { 536 JS_ThrowInternalError(ctx, "crypto_pwhash() call failed"); 537 goto exception; 538 } 539 ret_val = make_js_ta_copy(ctx, hash, hash_len); 540 done: 541 if (NULL != hash) { 542 free(hash); 543 } 544 return ret_val; 545 exception: 546 ret_val = JS_EXCEPTION; 547 goto done; 548 } 549 550 static JSValue js_talercrypto_eddsa_key_get_public(JSContext *ctx, JSValue this_val, 551 int argc, JSValueConst *argv) 552 { 553 JSValue ret; 554 uint8_t *buf; 555 unsigned char pk[crypto_sign_PUBLICKEYBYTES]; 556 unsigned char sk[crypto_sign_SECRETKEYBYTES]; 557 558 buf = expect_fixed_buffer(ctx, argv[0], crypto_sign_SEEDBYTES, 559 "eddsa private key seed"); 560 561 if (!buf) { 562 goto exception; 563 } 564 565 crypto_sign_seed_keypair(pk, sk, buf); 566 567 ret = make_js_ta_copy(ctx, pk, crypto_sign_PUBLICKEYBYTES); 568 done: 569 sodium_memzero(sk, sizeof sk); 570 return ret; 571 exception: 572 ret = JS_EXCEPTION; 573 goto done; 574 } 575 576 static JSValue js_talercrypto_ecdhe_key_get_public(JSContext *ctx, JSValue this_val, 577 int argc, JSValueConst *argv) 578 { 579 JSValue ret; 580 uint8_t *buf; 581 unsigned char pk[crypto_scalarmult_BYTES]; 582 583 buf = expect_fixed_buffer(ctx, argv[0], crypto_sign_SEEDBYTES, "ecdh private key seed"); 584 585 if (!buf) { 586 goto exception; 587 } 588 589 if (0 != crypto_scalarmult_base(pk, buf)) { 590 goto exception; 591 } 592 593 ret = make_js_ta_copy(ctx, pk, crypto_sign_PUBLICKEYBYTES); 594 done: 595 buf = NULL; 596 return ret; 597 exception: 598 ret = JS_EXCEPTION; 599 goto done; 600 } 601 602 /** 603 * (msg, priv) => sig 604 */ 605 static JSValue js_talercrypto_eddsa_sign(JSContext *ctx, JSValue this_val, 606 int argc, JSValueConst *argv) 607 { 608 unsigned char *seed; 609 size_t seed_size; 610 unsigned char *data; 611 size_t data_size; 612 unsigned char sk[crypto_sign_SECRETKEYBYTES]; 613 unsigned char pk[crypto_sign_PUBLICKEYBYTES]; 614 unsigned char sig[64]; 615 int res; 616 617 data = JS_GetArrayBuffer(ctx, &data_size, argv[0]); 618 if (!data) { 619 return JS_EXCEPTION; 620 } 621 622 seed = JS_GetArrayBuffer(ctx, &seed_size, argv[1]); 623 if (!seed) { 624 return JS_EXCEPTION; 625 } 626 if (seed_size != 32) { 627 return JS_ThrowTypeError(ctx, "invalid private key seed size"); 628 } 629 630 if (0 != crypto_sign_seed_keypair(pk, sk, seed)) { 631 return JS_EXCEPTION; 632 } 633 634 res = crypto_sign_detached((uint8_t *)sig, 635 NULL, 636 (uint8_t *)data, 637 data_size, 638 sk); 639 if (res != 0) { 640 return JS_EXCEPTION; 641 } 642 return make_js_ta_copy(ctx, sig, 64); 643 } 644 645 /** 646 * (msg, sig, pub) -> bool 647 */ 648 static JSValue js_talercrypto_eddsa_verify(JSContext *ctx, JSValue this_val, 649 int argc, JSValueConst *argv) 650 { 651 unsigned char *msg; 652 size_t msg_size; 653 unsigned char *sig; 654 size_t sig_size; 655 unsigned char *pub; 656 size_t pub_size; 657 int res; 658 659 msg = JS_GetArrayBuffer(ctx, &msg_size, argv[0]); 660 if (!msg) { 661 return JS_EXCEPTION; 662 } 663 sig = JS_GetArrayBuffer(ctx, &sig_size, argv[1]); 664 if (!sig) { 665 return JS_EXCEPTION; 666 } 667 if (sig_size != 64) { 668 return JS_ThrowTypeError(ctx, "invalid signature size"); 669 } 670 pub = JS_GetArrayBuffer(ctx, &pub_size, argv[2]); 671 if (!pub) { 672 return JS_EXCEPTION; 673 } 674 if (pub_size != 32) { 675 return JS_ThrowTypeError(ctx, "invalid public key size"); 676 } 677 678 res = crypto_sign_verify_detached (sig, msg, msg_size, pub); 679 return (res == 0) ? JS_TRUE : JS_FALSE; 680 } 681 682 /** 683 * Returns 0 on success. 684 */ 685 static int 686 kdf(void *okm, size_t okm_len, 687 const void *ikm, size_t ikm_len, 688 const void *salt, size_t salt_len, 689 const void *info, size_t info_len) 690 { 691 const mbedtls_md_info_t *md_extract; 692 const mbedtls_md_info_t *md_expand; 693 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 694 unsigned char prk[MBEDTLS_MD_MAX_SIZE]; 695 696 md_extract = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); 697 md_expand = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); 698 if (NULL == md_extract) { 699 return -1; 700 } 701 if (NULL == md_expand) { 702 return -1; 703 } 704 705 ret = mbedtls_hkdf_extract(md_extract, salt, salt_len, ikm, ikm_len, prk); 706 707 if (ret != 0) { 708 return ret; 709 } 710 711 ret = mbedtls_hkdf_expand(md_expand, prk, mbedtls_md_get_size(md_extract), 712 info, info_len, okm, okm_len); 713 return ret; 714 } 715 716 /** 717 * (outLen, ikm, salt?, info?) -> output 718 */ 719 static JSValue js_talercrypto_kdf(JSContext *ctx, JSValue this_val, 720 int argc, JSValueConst *argv) 721 { 722 size_t salt_len; 723 size_t ikm_len; 724 size_t info_len; 725 size_t okm_len; 726 uint8_t *salt; 727 uint8_t *ikm; 728 uint8_t *info; 729 uint8_t *okm = NULL; 730 uint32_t out_bytes; 731 JSValue ret_val; 732 int ret; 733 734 if (0 != JS_ToUint32(ctx, &out_bytes, argv[0])) { 735 goto exception; 736 } 737 okm_len = out_bytes; 738 739 ikm = JS_GetArrayBuffer(ctx, &ikm_len, argv[1]); 740 if (!ikm) { 741 goto exception; 742 } 743 744 if (JS_IsUndefined(argv[2])) { 745 salt = NULL; 746 salt_len = 0; 747 } else { 748 salt = JS_GetArrayBuffer(ctx, &salt_len, argv[2]); 749 if (!salt) { 750 goto exception; 751 } 752 } 753 754 if (JS_IsUndefined(argv[3])) { 755 info = NULL; 756 info_len = 0; 757 } else { 758 info = JS_GetArrayBuffer(ctx, &info_len, argv[3]); 759 if (!info) { 760 goto exception; 761 } 762 } 763 764 okm = malloc(okm_len); 765 766 ret = kdf(okm, okm_len, ikm, ikm_len, salt, salt_len, info, info_len); 767 768 if (ret != 0) { 769 JS_ThrowInternalError(ctx, "kdf() call failed"); 770 goto exception; 771 } 772 ret_val = make_js_ta_copy(ctx, okm, okm_len); 773 done: 774 if (NULL != okm) { 775 free(okm); 776 } 777 return ret_val; 778 exception: 779 ret_val = JS_EXCEPTION; 780 goto done; 781 } 782 783 /** 784 * (ecdhePriv, eddsaPub) -> keyMaterial 785 */ 786 static JSValue js_talercrypto_kx_ecdh_eddsa(JSContext *ctx, JSValue this_val, 787 int argc, JSValueConst *argv) 788 { 789 JSValue ret_val; 790 uint8_t p[crypto_scalarmult_BYTES]; 791 uint8_t *ecdh_priv; 792 uint8_t *eddsa_pub; 793 uint8_t curve25510_pk[crypto_scalarmult_BYTES]; 794 uint8_t key_material[crypto_hash_BYTES]; 795 796 ecdh_priv = expect_fixed_buffer(ctx, argv[0], 32, "ecdhe priv"); 797 REQUIRE(ecdh_priv, exception); 798 799 eddsa_pub = expect_fixed_buffer(ctx, argv[1], 32, "eddsa pub"); 800 REQUIRE(eddsa_pub, exception); 801 802 if (0 != crypto_sign_ed25519_pk_to_curve25519(curve25510_pk, eddsa_pub)) { 803 goto exception; 804 } 805 if (0 != crypto_scalarmult(p, ecdh_priv, curve25510_pk)) { 806 goto exception; 807 } 808 if (0 != crypto_hash(key_material, p, 32)) { 809 JS_ThrowTypeError(ctx, "hashing failed"); 810 goto exception; 811 } 812 ret_val = make_js_ta_copy(ctx, key_material, crypto_hash_BYTES); 813 done: 814 return ret_val; 815 exception: 816 ret_val = JS_EXCEPTION; 817 goto done; 818 } 819 820 /** 821 * (eddsaPriv, ecdhePub) -> keyMaterial 822 */ 823 static JSValue js_talercrypto_kx_eddsa_ecdh(JSContext *ctx, JSValue this_val, 824 int argc, JSValueConst *argv) 825 { 826 JSValue ret_val; 827 uint8_t *priv; 828 uint8_t *pub; 829 uint8_t hc[crypto_hash_BYTES]; 830 uint8_t a[crypto_scalarmult_SCALARBYTES]; 831 uint8_t p[crypto_scalarmult_BYTES]; 832 uint8_t key_material[crypto_hash_BYTES]; 833 834 priv = expect_fixed_buffer(ctx, argv[0], 32, "eddsa priv"); 835 REQUIRE(priv, exception); 836 pub = expect_fixed_buffer(ctx, argv[1], 32, "ecdh pub"); 837 REQUIRE(pub, exception); 838 839 crypto_hash(hc, priv, 32); 840 memcpy (a, &hc, 32); 841 if (0 != crypto_scalarmult(p, a, pub)) { 842 goto exception; 843 } 844 crypto_hash(key_material, p, crypto_scalarmult_BYTES); 845 ret_val = make_js_ta_copy(ctx, key_material, crypto_hash_BYTES); 846 done: 847 return ret_val; 848 exception: 849 ret_val = JS_EXCEPTION; 850 goto done; 851 } 852 853 /** FIXME: Should return int */ 854 void 855 kdf_mod_mpi(mbedtls_mpi *r, 856 const mbedtls_mpi *n, 857 const void *xts, size_t xts_len, 858 const void *skm, size_t skm_len, 859 const char *ctx) 860 { 861 int rc; 862 size_t nbits; 863 uint16_t ctr; 864 size_t ctxlen = strlen(ctx); 865 size_t my_ctx_len = ctxlen + 2; 866 unsigned char *my_ctx = malloc(my_ctx_len); 867 uint16_t *ctr_nbo_p = (uint16_t *) (my_ctx + ctxlen); 868 869 memcpy(my_ctx, ctx, ctxlen); 870 871 nbits = mbedtls_mpi_bitlen(n); 872 ctr = 0; 873 while (1) { 874 /* Not clear if n is always divisible by 8 */ 875 size_t bsize = (nbits - 1) / 8 + 1; 876 uint8_t buf[bsize]; 877 878 *ctr_nbo_p = htons (ctr); 879 880 rc = kdf (buf, bsize, 881 skm, skm_len, 882 xts, xts_len, 883 my_ctx, my_ctx_len); 884 CHECK(0 == rc); 885 rc = mbedtls_mpi_read_binary(r, buf, bsize); 886 CHECK(0 == rc); 887 while (1) { 888 size_t rlen = mbedtls_mpi_bitlen(r); 889 if (rlen <= nbits) { 890 break; 891 } 892 mbedtls_mpi_set_bit(r, rlen - 1, 0); 893 } 894 ++ctr; 895 /* We reject this FDH if either r > n and retry with another ctr */ 896 if (0 > mbedtls_mpi_cmp_mpi (r, n)) { 897 break; 898 } 899 mbedtls_mpi_free (r); 900 } 901 free(my_ctx); 902 } 903 904 905 /** 906 * Test for malicious RSA key. 907 * 908 * Assuming n is an RSA modulous and r is generated using a call to 909 * GNUNET_CRYPTO_kdf_mod_mpi, if gcd(r,n) != 1 then n must be a 910 * malicious RSA key designed to deanomize the user. 911 * 912 * @param r KDF result 913 * @param n RSA modulus 914 * @return 0 if gcd(r,n) = 1, 1 means RSA key is malicious, negative is syserror 915 */ 916 static int 917 rsa_gcd_validate (mbedtls_mpi *r, 918 const mbedtls_mpi *n) 919 { 920 mbedtls_mpi g; 921 int ret; 922 923 mbedtls_mpi_init(&g); 924 MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&g, r, n)); 925 926 if (mbedtls_mpi_cmp_int(&g, 1) == 0) { 927 ret = 0; 928 } else { 929 goto cleanup; 930 } 931 932 cleanup: 933 mbedtls_mpi_free(&g); 934 return ret; 935 } 936 937 938 int 939 rsa_blinding_key_derive(mbedtls_mpi *r, 940 const RsaPub *pkey, 941 const BlindingKeySecret *bks) 942 { 943 /* Trusts bks' randomness more */ 944 const char *xts = "Blinding KDF extractor HMAC key"; 945 946 kdf_mod_mpi(r, 947 &pkey->N, 948 xts, strlen(xts), 949 bks, sizeof(*bks), 950 "Blinding KDF"); 951 952 if (0 != rsa_gcd_validate (r, &pkey->N)) { 953 return -1; 954 } 955 956 return 0; 957 } 958 959 int 960 rsa_public_key_encode(const RsaPub *pkey, uint8_t **outbuf, size_t *outbuf_len) 961 { 962 size_t sz; 963 uint8_t *buf; 964 uint8_t *p; /* write pointer */ 965 size_t mod_len; 966 size_t exp_len; 967 int ret; 968 969 *outbuf = NULL; 970 *outbuf_len = 0; 971 972 mod_len = mbedtls_mpi_size(&pkey->N); 973 exp_len = mbedtls_mpi_size(&pkey->e); 974 sz = 2 + 2 + exp_len + mod_len; 975 buf = malloc(sz); 976 if (!buf) { 977 return -1; 978 } 979 980 p = buf; 981 *((uint16_t *) p) = htons(mod_len); 982 p += sizeof (uint16_t); 983 *((uint16_t *) p) = htons(exp_len); 984 p += sizeof (uint16_t); 985 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&pkey->N, p, mod_len)); 986 p += mod_len; 987 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&pkey->e, p, exp_len)); 988 989 *outbuf = buf; 990 *outbuf_len = sz; 991 992 cleanup: 993 if (0 != ret) { 994 free(buf); 995 } 996 return ret; 997 } 998 999 1000 void 1001 rsa_public_key_init(RsaPub *pkey) 1002 { 1003 CHECK(NULL != pkey); 1004 mbedtls_mpi_init(&pkey->e); 1005 mbedtls_mpi_init(&pkey->N); 1006 } 1007 1008 void 1009 rsa_public_key_free(RsaPub *pkey) 1010 { 1011 if (!pkey) { 1012 return; 1013 } 1014 mbedtls_mpi_free(&pkey->e); 1015 mbedtls_mpi_free(&pkey->N); 1016 } 1017 1018 1019 int 1020 rsa_full_domain_hash (mbedtls_mpi *r, const RsaPub *pkey, 1021 const HashCode *hash) 1022 { 1023 uint8_t *xts; 1024 size_t xts_len; 1025 1026 /* We key with the public denomination key as a homage to RSA-PSS by 1027 Mihir Bellare and Phillip Rogaway. Doing this lowers the degree 1028 of the hypothetical polyomial-time attack on RSA-KTI created by a 1029 polynomial-time one-more forgary attack. Yey seeding! */ 1030 rsa_public_key_encode(pkey, &xts, &xts_len); 1031 1032 kdf_mod_mpi(r, 1033 &pkey->N, 1034 xts, xts_len, 1035 hash, sizeof(*hash), 1036 "RSA-FDA FTpsW!"); 1037 free(xts); 1038 if (0 == rsa_gcd_validate (r, &pkey->N)) { 1039 return 0; 1040 } 1041 return 1; 1042 } 1043 1044 static int 1045 rsa_blind(const HashCode *hash, 1046 const BlindingKeySecret *bks, 1047 const RsaPub *pkey, 1048 uint8_t **buf, 1049 size_t *buf_size) 1050 { 1051 mbedtls_mpi bkey, data, r_e, data_r_e; 1052 size_t outsize; 1053 uint8_t *outbuf; 1054 int ret; 1055 1056 CHECK(buf != NULL); 1057 CHECK(buf_size != NULL); 1058 1059 *buf = NULL; 1060 *buf_size = 0; 1061 1062 mbedtls_mpi_init(&bkey); 1063 mbedtls_mpi_init(&data); 1064 mbedtls_mpi_init(&r_e); 1065 mbedtls_mpi_init(&data_r_e); 1066 1067 MBEDTLS_MPI_CHK(rsa_full_domain_hash (&data, pkey, hash)); 1068 MBEDTLS_MPI_CHK(rsa_blinding_key_derive (&bkey, pkey, bks)); 1069 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&r_e, &bkey, &pkey->e, &pkey->N, NULL)); 1070 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&data_r_e, &data, &r_e)); 1071 MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&data_r_e, &data_r_e, &pkey->N)); 1072 1073 outsize = (mbedtls_mpi_bitlen(&data_r_e) + 7) / 8; 1074 outbuf = malloc(outsize); 1075 1076 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&data_r_e, outbuf, outsize)); 1077 1078 *buf = outbuf; 1079 *buf_size = outsize; 1080 ret = 0; 1081 1082 cleanup: 1083 mbedtls_mpi_free(&data); 1084 mbedtls_mpi_free(&bkey); 1085 mbedtls_mpi_free(&r_e); 1086 mbedtls_mpi_free(&data_r_e); 1087 return ret; 1088 } 1089 1090 int 1091 rsa_unblind (const mbedtls_mpi *sig_blinded, 1092 const BlindingKeySecret *bks, 1093 const RsaPub *pkey, 1094 mbedtls_mpi *sig_ret) 1095 { 1096 mbedtls_mpi bkey, r_inv, ubsig; 1097 int ret; 1098 1099 mbedtls_mpi_init(&bkey); 1100 mbedtls_mpi_init(&r_inv); 1101 mbedtls_mpi_init(&ubsig); 1102 1103 MBEDTLS_MPI_CHK(rsa_blinding_key_derive (&bkey, pkey, bks)); 1104 MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&r_inv, &bkey, &pkey->N)); 1105 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ubsig, sig_blinded, &r_inv)); 1106 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(sig_ret, &ubsig)); 1107 1108 cleanup: 1109 mbedtls_mpi_free(&bkey); 1110 mbedtls_mpi_free(&r_inv); 1111 mbedtls_mpi_free(&ubsig); 1112 return ret; 1113 } 1114 1115 1116 int 1117 rsa_verify(const HashCode *hash, 1118 const mbedtls_mpi *sig, 1119 const RsaPub *pkey) 1120 { 1121 mbedtls_mpi r; 1122 mbedtls_mpi sig_e; 1123 int ret; 1124 1125 mbedtls_mpi_init(&r); 1126 mbedtls_mpi_init(&sig_e); 1127 1128 /* Can fail if RSA key is malicious since rsa_gcd_validate failed here. 1129 * It should have failed during GNUNET_CRYPTO_rsa_blind too though, 1130 * so the exchange is being malicious in an unfamilair way, maybe 1131 * just trying to crash us. Arguably, we've only an internal error 1132 * though because we should've detected this in our previous call 1133 * to GNUNET_CRYPTO_rsa_unblind. */// 1134 MBEDTLS_MPI_CHK(rsa_full_domain_hash(&r, pkey, hash)); 1135 1136 MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&sig_e, sig, &pkey->e, &pkey->N, NULL)); 1137 1138 if (0 != mbedtls_mpi_cmp_mpi(&r, &sig_e)) { 1139 ret = -1; 1140 } else { 1141 ret = 0; 1142 } 1143 1144 cleanup: 1145 mbedtls_mpi_free(&r); 1146 mbedtls_mpi_free(&sig_e); 1147 return ret; 1148 } 1149 1150 1151 /** 1152 * (hmsg, bks, rsaPub) -> blinded 1153 */ 1154 static JSValue js_talercrypto_rsa_blind(JSContext *ctx, JSValueConst this_val, 1155 int argc, JSValueConst *argv) 1156 { 1157 HashCode *hmsg; 1158 BlindingKeySecret *bks; 1159 uint8_t *rsa_enc; 1160 size_t rsa_enc_len; 1161 RsaPub rsa_pub; 1162 JSValue ret_val = JS_UNDEFINED; 1163 uint8_t *out_buf = NULL; 1164 size_t out_len; 1165 1166 rsa_public_key_init(&rsa_pub); 1167 1168 hmsg = (HashCode *) expect_fixed_buffer(ctx, argv[0], 64, "hmsg"); 1169 if (!hmsg) { 1170 ret_val = JS_EXCEPTION; 1171 goto cleanup; 1172 } 1173 bks = (BlindingKeySecret *) expect_fixed_buffer(ctx, argv[1], 32, "bks"); 1174 if (!bks) { 1175 ret_val = JS_EXCEPTION; 1176 goto cleanup; 1177 } 1178 rsa_enc = JS_GetArrayBuffer(ctx, &rsa_enc_len, argv[2]); 1179 if (!rsa_enc) { 1180 ret_val = JS_EXCEPTION; 1181 goto cleanup; 1182 } 1183 if (0 != rsa_public_key_decode(&rsa_pub, rsa_enc, rsa_enc_len)) { 1184 ret_val = JS_ThrowTypeError(ctx, "rsa pubkey"); 1185 goto cleanup; 1186 } 1187 if (0 != rsa_blind(hmsg, bks, &rsa_pub, &out_buf, &out_len)) { 1188 ret_val = JS_ThrowInternalError(ctx, "blinding failed"); 1189 goto cleanup; 1190 } 1191 1192 ret_val = make_js_ta_copy(ctx, out_buf, out_len); 1193 cleanup: 1194 if (NULL != out_buf) { 1195 free(out_buf); 1196 out_buf = NULL; 1197 } 1198 rsa_public_key_free(&rsa_pub); 1199 return ret_val; 1200 } 1201 1202 /** 1203 * (blindSig, rsaPub, bks) -> ubsig 1204 */ 1205 static JSValue js_talercrypto_rsa_unblind(JSContext *ctx, JSValueConst this_val, 1206 int argc, JSValueConst *argv) 1207 { 1208 JSValue ret_val = JS_UNDEFINED; 1209 mbedtls_mpi bsig; 1210 mbedtls_mpi sig_ret; 1211 RsaPub rsa_pub; 1212 BlindingKeySecret *bks; 1213 1214 mbedtls_mpi_init(&bsig); 1215 mbedtls_mpi_init(&sig_ret); 1216 rsa_public_key_init(&rsa_pub); 1217 1218 if (0 != expect_mpi(ctx, argv[0], "blindSig", &bsig)) { 1219 ret_val = JS_EXCEPTION; 1220 goto cleanup; 1221 } 1222 if (0 != expect_rsa_pub(ctx, argv[1], "rsaPub", &rsa_pub)) { 1223 ret_val = JS_EXCEPTION; 1224 goto cleanup; 1225 } 1226 bks = (BlindingKeySecret *) expect_fixed_buffer(ctx, argv[2], 32, "bks"); 1227 if (!bks) { 1228 ret_val = JS_EXCEPTION; 1229 goto cleanup; 1230 } 1231 1232 if (0 != rsa_unblind(&bsig, bks, &rsa_pub, &sig_ret)) { 1233 ret_val = JS_ThrowInternalError(ctx, "unblinding failed"); 1234 goto cleanup; 1235 } 1236 1237 ret_val = make_js_ta_mpi(ctx, &sig_ret); 1238 1239 cleanup: 1240 mbedtls_mpi_free(&bsig); 1241 mbedtls_mpi_free(&sig_ret); 1242 rsa_public_key_free(&rsa_pub); 1243 return ret_val; 1244 } 1245 1246 /** 1247 * (hm, rsaSig, rsaPub) -> bool 1248 */ 1249 static JSValue js_talercrypto_rsa_verify(JSContext *ctx, JSValueConst this_val, 1250 int argc, JSValueConst *argv) 1251 { 1252 JSValue ret_val = JS_UNDEFINED; 1253 HashCode *hmsg; 1254 mbedtls_mpi sig; 1255 RsaPub rsa_pub; 1256 1257 mbedtls_mpi_init(&sig); 1258 rsa_public_key_init(&rsa_pub); 1259 1260 hmsg = (HashCode *) expect_fixed_buffer(ctx, argv[0], 64, "hmsg"); 1261 if (!hmsg) { 1262 ret_val = JS_EXCEPTION; 1263 goto cleanup; 1264 } 1265 1266 if (0 != expect_mpi(ctx, argv[1], "sig", &sig)) { 1267 ret_val = JS_EXCEPTION; 1268 goto cleanup; 1269 } 1270 1271 if (0 != expect_rsa_pub(ctx, argv[2], "rsaPub", &rsa_pub)) { 1272 ret_val = JS_EXCEPTION; 1273 goto cleanup; 1274 } 1275 1276 if (0 != rsa_verify(hmsg, &sig, &rsa_pub)) { 1277 ret_val = JS_FALSE; 1278 goto cleanup; 1279 } 1280 1281 ret_val = JS_TRUE; 1282 1283 cleanup: 1284 mbedtls_mpi_free(&sig); 1285 rsa_public_key_free(&rsa_pub); 1286 return ret_val; 1287 1288 } 1289 1290 // (ArrayBuffer | TypedArray) => string 1291 static JSValue js_decode_utf8(JSContext *ctx, JSValueConst this_val, 1292 int argc, JSValueConst *argv) 1293 { 1294 size_t psize; 1295 uint8_t *utf8_buf; 1296 JSValue ret_val; 1297 1298 utf8_buf = JS_GetArrayBuffer(ctx, &psize, argv[0]); 1299 if (NULL == utf8_buf) { 1300 goto exception; 1301 } 1302 return JS_NewStringLen(ctx, (char *) utf8_buf, psize); 1303 done: 1304 return ret_val; 1305 exception: 1306 ret_val = JS_EXCEPTION; 1307 goto done; 1308 } 1309 1310 static JSValue js_structured_clone(JSContext *ctx, JSValueConst this_val, 1311 int argc, JSValueConst *argv) 1312 { 1313 uint8_t *buf; 1314 size_t len; 1315 JSValue obj; 1316 1317 buf = JS_WriteObject(ctx, &len, argv[0], JS_WRITE_OBJ_REFERENCE); 1318 1319 if (NULL == buf) { 1320 return JS_EXCEPTION; 1321 } 1322 1323 obj = JS_ReadObject(ctx, buf, len, JS_WRITE_OBJ_REFERENCE); 1324 js_free(ctx, buf); 1325 return obj; 1326 } 1327 1328 static JSClassID js_hash_state_class_id; 1329 1330 typedef struct { 1331 crypto_hash_sha512_state h; 1332 int finalized; 1333 } TART_HashState; 1334 1335 1336 static void js_hash_state_finalizer(JSRuntime *rt, JSValue val) 1337 { 1338 TART_HashState *s = JS_GetOpaque(val, js_hash_state_class_id); 1339 /* Note: 's' can be NULL in case JS_SetOpaque() was not called */ 1340 js_free_rt(rt, s); 1341 } 1342 1343 static JSClassDef js_hash_state_class = { 1344 "HashState", 1345 .finalizer = js_hash_state_finalizer, 1346 }; 1347 1348 static JSValue js_talercrypto_hash_state_init(JSContext *ctx, JSValue this_val, 1349 int argc, JSValueConst *argv) 1350 { 1351 TART_HashState *hstate; 1352 JSValue obj; 1353 1354 hstate = js_malloc_rt(JS_GetRuntime(ctx), sizeof (TART_HashState)); 1355 if (!hstate) { 1356 obj = JS_EXCEPTION; 1357 goto done; 1358 } 1359 hstate->finalized = FALSE; 1360 obj = JS_NewObjectClass(ctx, js_hash_state_class_id); 1361 crypto_hash_sha512_init(&hstate->h); 1362 JS_SetOpaque(obj, hstate); 1363 hstate = NULL; 1364 return obj; 1365 done: 1366 if (NULL != hstate) { 1367 js_free_rt(JS_GetRuntime(ctx), hstate); 1368 } 1369 return obj; 1370 } 1371 1372 static JSValue js_talercrypto_hash_state_update(JSContext *ctx, JSValue this_val, 1373 int argc, JSValueConst *argv) 1374 { 1375 JSValue state = argv[0]; 1376 JSValue data_val = argv[1]; 1377 TART_HashState *hstate; 1378 uint8_t *data; 1379 size_t data_len; 1380 1381 hstate = JS_GetOpaque(state, js_hash_state_class_id); 1382 1383 if (!hstate) { 1384 return JS_ThrowTypeError(ctx, "expected HashState"); 1385 } 1386 1387 if (hstate->finalized) { 1388 return JS_ThrowTypeError(ctx, "already finalized"); 1389 } 1390 1391 data = JS_GetArrayBuffer(ctx, &data_len, data_val); 1392 1393 if (0 != crypto_hash_sha512_update(&hstate->h, data, data_len)) { 1394 return JS_ThrowInternalError(ctx, "hashing failed"); 1395 } 1396 1397 return JS_UNDEFINED; 1398 } 1399 1400 static JSValue js_talercrypto_hash_state_finish(JSContext *ctx, JSValue this_val, 1401 int argc, JSValueConst *argv) 1402 { 1403 JSValue state = argv[0]; 1404 TART_HashState *hstate; 1405 uint8_t hashval[crypto_hash_sha512_BYTES]; 1406 1407 hstate = JS_GetOpaque(state, js_hash_state_class_id); 1408 1409 if (!hstate) { 1410 return JS_ThrowTypeError(ctx, "expected HashState"); 1411 } 1412 1413 if (hstate->finalized) { 1414 return JS_ThrowTypeError(ctx, "already finalized"); 1415 } 1416 1417 if (0 != crypto_hash_sha512_final(&hstate->h, hashval)) { 1418 return JS_ThrowInternalError(ctx, "hashing failed"); 1419 } 1420 1421 hstate->finalized = TRUE; 1422 1423 return make_js_ta_copy(ctx, hashval, crypto_hash_sha512_BYTES); 1424 } 1425 1426 static JSClassID js_sqlite3_database_class_id; 1427 static JSClassID js_sqlite3_statement_class_id; 1428 1429 static void js_sqlite3_database_finalizer(JSRuntime *rt, JSValue val) 1430 { 1431 sqlite3 *sqlite3_db; 1432 sqlite3_db = JS_GetOpaque(val, js_sqlite3_database_class_id); 1433 (void)sqlite3_close_v2(sqlite3_db); 1434 JS_SetOpaque(val, NULL); 1435 } 1436 1437 static void js_sqlite3_statement_finalizer(JSRuntime *rt, JSValue val) 1438 { 1439 sqlite3_stmt *stmt; 1440 1441 stmt = JS_GetOpaque(val, js_sqlite3_statement_class_id); 1442 // FIXME: Check error code and warn? 1443 sqlite3_finalize(stmt); 1444 JS_SetOpaque(val, NULL); 1445 } 1446 1447 static JSClassDef js_sqlite3_database_class = { 1448 .class_name = "Sqlite3Database", 1449 .finalizer = js_sqlite3_database_finalizer, 1450 }; 1451 1452 static JSClassDef js_sqlite3_statement_class = { 1453 .class_name = "Sqlite3Statement", 1454 .finalizer = js_sqlite3_statement_finalizer, 1455 }; 1456 1457 #define ERRCASE(c) case c: return #c 1458 1459 const char *translate_sqlite3_err_to_string(int errcode) 1460 { 1461 switch (errcode) { 1462 ERRCASE(SQLITE_OK); 1463 ERRCASE(SQLITE_ERROR); 1464 ERRCASE(SQLITE_INTERNAL); 1465 ERRCASE(SQLITE_PERM); 1466 ERRCASE(SQLITE_ABORT); 1467 ERRCASE(SQLITE_BUSY); 1468 ERRCASE(SQLITE_LOCKED); 1469 ERRCASE(SQLITE_NOMEM); 1470 ERRCASE(SQLITE_READONLY); 1471 ERRCASE(SQLITE_INTERRUPT); 1472 ERRCASE(SQLITE_IOERR); 1473 ERRCASE(SQLITE_CORRUPT); 1474 ERRCASE(SQLITE_NOTFOUND); 1475 ERRCASE(SQLITE_FULL); 1476 ERRCASE(SQLITE_CANTOPEN); 1477 ERRCASE(SQLITE_PROTOCOL); 1478 ERRCASE(SQLITE_EMPTY); 1479 ERRCASE(SQLITE_SCHEMA); 1480 ERRCASE(SQLITE_TOOBIG); 1481 ERRCASE(SQLITE_CONSTRAINT); 1482 ERRCASE(SQLITE_MISMATCH); 1483 ERRCASE(SQLITE_MISUSE); 1484 ERRCASE(SQLITE_NOLFS); 1485 ERRCASE(SQLITE_AUTH); 1486 ERRCASE(SQLITE_FORMAT); 1487 ERRCASE(SQLITE_RANGE); 1488 ERRCASE(SQLITE_NOTADB); 1489 ERRCASE(SQLITE_NOTICE); 1490 ERRCASE(SQLITE_WARNING); 1491 ERRCASE(SQLITE_ROW); 1492 ERRCASE(SQLITE_DONE); 1493 ERRCASE(SQLITE_ERROR_MISSING_COLLSEQ); 1494 ERRCASE(SQLITE_ERROR_RETRY); 1495 ERRCASE(SQLITE_ERROR_SNAPSHOT); 1496 ERRCASE(SQLITE_IOERR_READ); 1497 ERRCASE(SQLITE_IOERR_SHORT_READ); 1498 ERRCASE(SQLITE_IOERR_WRITE); 1499 ERRCASE(SQLITE_IOERR_FSYNC); 1500 ERRCASE(SQLITE_IOERR_DIR_FSYNC); 1501 ERRCASE(SQLITE_IOERR_TRUNCATE); 1502 ERRCASE(SQLITE_IOERR_FSTAT); 1503 ERRCASE(SQLITE_IOERR_UNLOCK); 1504 ERRCASE(SQLITE_IOERR_RDLOCK); 1505 ERRCASE(SQLITE_IOERR_DELETE); 1506 ERRCASE(SQLITE_IOERR_BLOCKED); 1507 ERRCASE(SQLITE_IOERR_NOMEM); 1508 ERRCASE(SQLITE_IOERR_ACCESS); 1509 ERRCASE(SQLITE_IOERR_CHECKRESERVEDLOCK); 1510 ERRCASE(SQLITE_IOERR_LOCK); 1511 ERRCASE(SQLITE_IOERR_CLOSE); 1512 ERRCASE(SQLITE_IOERR_DIR_CLOSE); 1513 ERRCASE(SQLITE_IOERR_SHMOPEN); 1514 ERRCASE(SQLITE_IOERR_SHMSIZE); 1515 ERRCASE(SQLITE_IOERR_SHMLOCK); 1516 ERRCASE(SQLITE_IOERR_SHMMAP); 1517 ERRCASE(SQLITE_IOERR_SEEK); 1518 ERRCASE(SQLITE_IOERR_DELETE_NOENT); 1519 ERRCASE(SQLITE_IOERR_MMAP); 1520 ERRCASE(SQLITE_IOERR_GETTEMPPATH); 1521 ERRCASE(SQLITE_IOERR_CONVPATH); 1522 ERRCASE(SQLITE_IOERR_VNODE); 1523 ERRCASE(SQLITE_IOERR_AUTH); 1524 ERRCASE(SQLITE_IOERR_BEGIN_ATOMIC); 1525 ERRCASE(SQLITE_IOERR_COMMIT_ATOMIC); 1526 ERRCASE(SQLITE_IOERR_ROLLBACK_ATOMIC); 1527 ERRCASE(SQLITE_IOERR_DATA); 1528 ERRCASE(SQLITE_IOERR_CORRUPTFS); 1529 ERRCASE(SQLITE_LOCKED_SHAREDCACHE); 1530 ERRCASE(SQLITE_LOCKED_VTAB); 1531 ERRCASE(SQLITE_BUSY_RECOVERY); 1532 ERRCASE(SQLITE_BUSY_SNAPSHOT); 1533 ERRCASE(SQLITE_BUSY_TIMEOUT); 1534 ERRCASE(SQLITE_CANTOPEN_NOTEMPDIR); 1535 ERRCASE(SQLITE_CANTOPEN_ISDIR); 1536 ERRCASE(SQLITE_CANTOPEN_FULLPATH); 1537 ERRCASE(SQLITE_CANTOPEN_CONVPATH); 1538 ERRCASE(SQLITE_CANTOPEN_DIRTYWAL); 1539 ERRCASE(SQLITE_CANTOPEN_SYMLINK); 1540 ERRCASE(SQLITE_CORRUPT_VTAB); 1541 ERRCASE(SQLITE_CORRUPT_SEQUENCE); 1542 ERRCASE(SQLITE_CORRUPT_INDEX); 1543 ERRCASE(SQLITE_READONLY_RECOVERY); 1544 ERRCASE(SQLITE_READONLY_CANTLOCK); 1545 ERRCASE(SQLITE_READONLY_ROLLBACK); 1546 ERRCASE(SQLITE_READONLY_DBMOVED); 1547 ERRCASE(SQLITE_READONLY_CANTINIT); 1548 ERRCASE(SQLITE_READONLY_DIRECTORY); 1549 ERRCASE(SQLITE_ABORT_ROLLBACK); 1550 ERRCASE(SQLITE_CONSTRAINT_CHECK); 1551 ERRCASE(SQLITE_CONSTRAINT_COMMITHOOK); 1552 ERRCASE(SQLITE_CONSTRAINT_FOREIGNKEY); 1553 ERRCASE(SQLITE_CONSTRAINT_FUNCTION); 1554 ERRCASE(SQLITE_CONSTRAINT_NOTNULL); 1555 ERRCASE(SQLITE_CONSTRAINT_PRIMARYKEY); 1556 ERRCASE(SQLITE_CONSTRAINT_TRIGGER); 1557 ERRCASE(SQLITE_CONSTRAINT_UNIQUE); 1558 ERRCASE(SQLITE_CONSTRAINT_VTAB); 1559 ERRCASE(SQLITE_CONSTRAINT_ROWID); 1560 ERRCASE(SQLITE_CONSTRAINT_PINNED); 1561 ERRCASE(SQLITE_CONSTRAINT_DATATYPE); 1562 ERRCASE(SQLITE_NOTICE_RECOVER_WAL); 1563 ERRCASE(SQLITE_NOTICE_RECOVER_ROLLBACK); 1564 #ifdef SQLITE_NOTICE_RBU 1565 ERRCASE(SQLITE_NOTICE_RBU); 1566 #endif 1567 ERRCASE(SQLITE_WARNING_AUTOINDEX); 1568 ERRCASE(SQLITE_AUTH_USER); 1569 ERRCASE(SQLITE_OK_LOAD_PERMANENTLY); 1570 ERRCASE(SQLITE_OK_SYMLINK); 1571 default: 1572 return "SQLITE_UNKNOWN_ERRCODE"; 1573 } 1574 } 1575 1576 1577 static JSValue throw_sqlite3_error(JSContext *ctx, sqlite3 *db) 1578 { 1579 JSValue obj; 1580 1581 obj = JS_NewError(ctx); 1582 if (JS_IsException(obj)) { 1583 /* out of memory: throw JS_NULL to avoid recursing */ 1584 obj = JS_NULL; 1585 goto done; 1586 } 1587 1588 JS_DefinePropertyValueStr( 1589 ctx, 1590 obj, 1591 "message", 1592 JS_NewString(ctx, sqlite3_errmsg(db)), 1593 JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); 1594 1595 JS_DefinePropertyValueStr( 1596 ctx, 1597 obj, 1598 "code", 1599 JS_NewString(ctx, translate_sqlite3_err_to_string(sqlite3_errcode(db))), 1600 JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); 1601 1602 done: 1603 return JS_Throw(ctx, obj); 1604 } 1605 1606 1607 #define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1) 1608 #define MIN_SAFE_INTEGER (-(((int64_t)1 << 53) - 1)) 1609 1610 // (path: string, options?: { readonly?: boolean = false }) => Sqlite3Database 1611 static JSValue js_sqlite3_open(JSContext *ctx, JSValue this_val, 1612 int argc, JSValueConst *argv) 1613 { 1614 JSValue ret_val = JS_UNINITIALIZED; 1615 JSValue db_obj = JS_UNINITIALIZED; 1616 const char *filename = NULL; 1617 sqlite3 *sqlite3_db = NULL; 1618 int ret; 1619 1620 if (!JS_IsString(argv[0])) { 1621 ret_val = JS_ThrowTypeError(ctx, "filename argument required"); 1622 goto done; 1623 } 1624 1625 filename = JS_ToCString(ctx, argv[0]); 1626 1627 if (!filename) { 1628 ret_val = JS_ThrowTypeError(ctx, "filename argument required"); 1629 goto done; 1630 } 1631 1632 // fprintf(stderr, "opening sqlite3 db at %s\n", filename), 1633 ret = sqlite3_open_v2(filename, &sqlite3_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL); 1634 if (SQLITE_OK != ret) { 1635 if (NULL == sqlite3_db) { 1636 // sqlite3 was unable to even allocate memory 1637 ret_val = JS_ThrowInternalError(ctx, "unable to open database (OOM)"); 1638 } else { 1639 // get error details from DB before we close it 1640 fprintf(stderr, "sqlite3_open failed: %s / %s\n", 1641 sqlite3_errstr(ret), 1642 sqlite3_errmsg(sqlite3_db)); 1643 ret_val = throw_sqlite3_error(ctx, sqlite3_db); 1644 fprintf(stderr, "calling sqlite3 close on failed db\n"); 1645 (void)sqlite3_close_v2(sqlite3_db); 1646 } 1647 goto done; 1648 } 1649 db_obj = JS_NewObjectClass(ctx, js_sqlite3_database_class_id); 1650 JS_SetOpaque(db_obj, sqlite3_db); 1651 ret_val = db_obj; 1652 done: 1653 JS_FreeCString(ctx, filename); 1654 return ret_val; 1655 } 1656 1657 // (handle: Sqlite3Database) -> undefined 1658 static JSValue js_sqlite3_close(JSContext *ctx, JSValue this_val, 1659 int argc, JSValueConst *argv) 1660 { 1661 JSValue db_handle = argv[0]; 1662 sqlite3 *sqlite3_db; 1663 1664 sqlite3_db = JS_GetOpaque(db_handle, js_sqlite3_database_class_id); 1665 1666 if (!sqlite3_db) { 1667 return JS_ThrowTypeError(ctx, "invalid sqlite3 database handle"); 1668 } 1669 1670 (void) sqlite3_close_v2(sqlite3_db); 1671 JS_SetOpaque(db_handle, NULL); 1672 return JS_UNDEFINED; 1673 } 1674 1675 // (handle: Sqlite3Database, stmt: string) => Sqlite3Statement 1676 static JSValue js_sqlite3_prepare(JSContext *ctx, JSValue this_val, 1677 int argc, JSValueConst *argv) 1678 { 1679 JSValue db_handle = argv[0]; 1680 JSValue stmt_str = argv[1]; 1681 JSValue ret_val = JS_UNDEFINED; 1682 JSValue stmt_obj = JS_UNDEFINED; 1683 int ret; 1684 sqlite3 *sqlite3_db; 1685 sqlite3_stmt *stmt; 1686 const char *stmt_cstr; 1687 const char *tail; 1688 1689 sqlite3_db = JS_GetOpaque(db_handle, js_sqlite3_database_class_id); 1690 1691 if (!sqlite3_db) { 1692 return JS_ThrowTypeError(ctx, "invalid sqlite3 database handle"); 1693 } 1694 1695 stmt_cstr = JS_ToCString(ctx, stmt_str); 1696 1697 if (!stmt_cstr) { 1698 ret_val = JS_ThrowTypeError(ctx, "invalid prepared statement, string expected"); 1699 goto done; 1700 } 1701 1702 ret = sqlite3_prepare_v3(sqlite3_db, stmt_cstr, (int) strlen(stmt_cstr), 0, &stmt, &tail); 1703 if (SQLITE_OK != ret) { 1704 ret_val = JS_ThrowTypeError(ctx, "unable to prepare"); 1705 goto done; 1706 } 1707 1708 stmt_obj = JS_NewObjectClass(ctx, js_sqlite3_statement_class_id); 1709 JS_SetOpaque(stmt_obj, stmt); 1710 ret_val = stmt_obj; 1711 done: 1712 JS_FreeCString(ctx, stmt_cstr); 1713 return ret_val; 1714 } 1715 1716 1717 static JSValue js_sqlite3_finalize(JSContext *ctx, JSValue this_val, 1718 int argc, JSValueConst *argv) 1719 { 1720 sqlite3_stmt *stmt; 1721 1722 stmt = JS_GetOpaque(argv[0], js_sqlite3_statement_class_id); 1723 if (!stmt) { 1724 return JS_ThrowTypeError(ctx, "unable to finalize (not a statement)"); 1725 } 1726 // FIXME: Check error code and warn? 1727 sqlite3_finalize(stmt); 1728 JS_SetOpaque(argv[0], NULL); 1729 return JS_UNDEFINED; 1730 } 1731 1732 static int sql_exec_cb(void *cls, int numcol, char **res, char **colnames) { 1733 printf("got row with %d columns\n", numcol); 1734 return 0; 1735 } 1736 1737 static JSValue js_sqlite3_exec(JSContext *ctx, JSValue this_val, 1738 int argc, JSValueConst *argv) 1739 { 1740 sqlite3 *sqlite3_db; 1741 JSValue db_handle = argv[0]; 1742 JSValue stmt_str = argv[1]; 1743 const char *stmt_cstr = NULL; 1744 int res; 1745 char *errmsg = NULL; 1746 JSValue ret_val = JS_UNDEFINED; 1747 1748 sqlite3_db = JS_GetOpaque(db_handle, js_sqlite3_database_class_id); 1749 if (!sqlite3_db) { 1750 JS_ThrowTypeError(ctx, "invalid sqlite3 database handle"); 1751 goto exception; 1752 } 1753 stmt_cstr = JS_ToCString(ctx, stmt_str); 1754 if (!stmt_cstr) { 1755 goto exception; 1756 } 1757 res = sqlite3_exec(sqlite3_db, stmt_cstr, &sql_exec_cb, NULL, &errmsg); 1758 if (SQLITE_OK != res) { 1759 throw_sqlite3_error(ctx, sqlite3_db); 1760 goto exception; 1761 } 1762 done: 1763 sqlite3_free(errmsg); 1764 JS_FreeCString(ctx, stmt_cstr); 1765 return ret_val; 1766 exception: 1767 ret_val = JS_EXCEPTION; 1768 goto done; 1769 } 1770 1771 static int find_param_index(sqlite3_stmt *stmt, const char *name) 1772 { 1773 int param_index; 1774 char *prefixed_name = malloc(strlen(name) + 2); 1775 memcpy(prefixed_name + 1, name, strlen(name) + 1); 1776 1777 prefixed_name[0] = '$'; 1778 param_index = sqlite3_bind_parameter_index(stmt, prefixed_name); 1779 if (param_index) { 1780 goto done; 1781 } 1782 prefixed_name[0] = ':'; 1783 param_index = sqlite3_bind_parameter_index(stmt, prefixed_name); 1784 if (param_index) { 1785 goto done; 1786 } 1787 prefixed_name[0] = '@'; 1788 param_index = sqlite3_bind_parameter_index(stmt, prefixed_name); 1789 if (param_index) { 1790 goto done; 1791 } 1792 done: 1793 free(prefixed_name); 1794 return param_index; 1795 } 1796 1797 static int bind_from_object(JSContext *ctx, sqlite3_stmt *stmt, JSValueConst obj) 1798 { 1799 JSValue val; 1800 int i; 1801 uint32_t len = 0; /* len of property table */ 1802 JSPropertyEnum *tab; 1803 const char *key = NULL; 1804 int retval = 0; 1805 1806 if (JS_IsUndefined(obj)) { 1807 return 0; 1808 } 1809 1810 if (JS_GetOwnPropertyNames(ctx, &tab, &len, obj, 1811 JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) { 1812 JS_ThrowTypeError(ctx, "can't get property names"); 1813 return -1; 1814 } 1815 1816 for (i = 0; i < len; i++) { 1817 int param_index; 1818 val = JS_GetProperty(ctx, obj, tab[i].atom); 1819 if (JS_IsException(val)) 1820 goto fail; 1821 key = JS_AtomToCString(ctx, tab[i].atom); 1822 if (!key) { 1823 goto fail; 1824 } 1825 param_index = find_param_index(stmt, key); 1826 if (0 == param_index) { 1827 // JS_ThrowTypeError(ctx, "unable to bind, named param '%s' not found", key); 1828 //goto fail; 1829 // We ignore parameters that are bound but not used. 1830 goto next; 1831 } 1832 if (JS_IsNull(val)) { 1833 sqlite3_bind_null(stmt, param_index); 1834 goto next; 1835 } 1836 if (JS_IsString(val)) { 1837 const char *cstr; 1838 cstr = JS_ToCString(ctx, val); 1839 sqlite3_bind_text(stmt, param_index, cstr, (int) strlen(cstr), SQLITE_TRANSIENT); 1840 JS_FreeCString(ctx, cstr); 1841 goto next; 1842 } 1843 if (JS_IsNumber(val)) { 1844 int64_t n; 1845 JS_ToInt64(ctx, &n, val); 1846 sqlite3_bind_int64(stmt, param_index, n); 1847 goto next; 1848 } 1849 if (JS_IsArrayBuffer(val)) { 1850 uint8_t *data; 1851 size_t size; 1852 data = JS_GetArrayBuffer(ctx, &size, val); 1853 if (!data) { 1854 goto fail; 1855 } 1856 sqlite3_bind_blob(stmt, param_index, data, (int) size, SQLITE_TRANSIENT); 1857 goto next; 1858 } 1859 JS_ThrowTypeError(ctx, "unable to bind, unsupported type for arg %s", key); 1860 goto fail; 1861 next: 1862 JS_FreeCString(ctx, key); 1863 JS_FreeValue(ctx, val); 1864 } 1865 done: 1866 for (i = 0; i < len; i++) { 1867 JS_FreeAtom(ctx, tab[i].atom); 1868 } 1869 js_free(ctx, tab); 1870 return retval; 1871 fail: 1872 retval = -1; 1873 goto done; 1874 } 1875 1876 1877 static JSValue js_sqlite3_stmt_run(JSContext *ctx, JSValue this_val, 1878 int argc, JSValueConst *argv) 1879 { 1880 JSValue ret_val = JS_UNDEFINED; 1881 JSValue stmt_handle = argv[0]; 1882 sqlite3_stmt *stmt; 1883 sqlite3 *db; 1884 int sqlret; 1885 1886 stmt = JS_GetOpaque(stmt_handle, js_sqlite3_statement_class_id); 1887 if (!stmt) { 1888 ret_val = JS_ThrowTypeError(ctx, "invalid sqlite3 database handle"); 1889 goto done; 1890 } 1891 db = sqlite3_db_handle(stmt); 1892 // Reset is not strictly necessary, we do it anyway just to be safe 1893 sqlret = sqlite3_reset(stmt); 1894 if (SQLITE_OK != sqlret) { 1895 fprintf(stderr, "sqlite3_reset failed (in stmt_run): %s\n", sqlite3_errmsg(db)); 1896 ret_val = JS_ThrowTypeError(ctx, "failed to reset"); 1897 goto done; 1898 } 1899 sqlret = sqlite3_clear_bindings(stmt); 1900 if (SQLITE_OK != sqlret) { 1901 ret_val = JS_ThrowTypeError(ctx, "failed to clear bindings"); 1902 goto done; 1903 } 1904 if (argc > 1) { 1905 if (0 != bind_from_object(ctx, stmt, argv[1])) { 1906 ret_val = JS_EXCEPTION; 1907 goto done; 1908 } 1909 } 1910 while (1) { 1911 sqlret = sqlite3_step(stmt); 1912 switch (sqlret) { 1913 case SQLITE_ROW: 1914 break; 1915 case SQLITE_DONE: { 1916 JSValue rowid_val; 1917 ret_val = JS_NewObject(ctx); 1918 sqlite3_int64 rowid = sqlite3_last_insert_rowid(db); 1919 if (rowid >= MIN_SAFE_INTEGER && rowid <= MAX_SAFE_INTEGER) { 1920 rowid_val = JS_NewInt64(ctx, rowid); 1921 } else { 1922 rowid_val = JS_NewBigInt64(ctx, rowid); 1923 } 1924 JS_SetPropertyStr(ctx, ret_val, "lastInsertRowid", rowid_val); 1925 sqlret = sqlite3_reset(stmt); 1926 if (SQLITE_OK != sqlret) { 1927 fprintf(stderr, "sqlite3_reset failed (in stmt_run after SQLITE_DONE): %s\n", sqlite3_errmsg(db)); 1928 JS_FreeValue(ctx, ret_val); 1929 ret_val = JS_ThrowTypeError(ctx, "failed to reset"); 1930 goto done; 1931 } 1932 goto done; 1933 } 1934 default: 1935 ret_val = throw_sqlite3_error(ctx, db); 1936 sqlite3_reset(stmt); 1937 goto done; 1938 } 1939 } 1940 done: 1941 return ret_val; 1942 } 1943 1944 1945 static int extract_result_row(JSContext *ctx, sqlite3_stmt *stmt, JSValueConst target) 1946 { 1947 int colcount; 1948 int i; 1949 1950 colcount = sqlite3_column_count(stmt); 1951 1952 for (i = 0; i < colcount; i++) { 1953 const char *colname = sqlite3_column_name(stmt, i); 1954 int coltype = sqlite3_column_type(stmt, i); 1955 switch (coltype) { 1956 case SQLITE_INTEGER: { 1957 int64_t val = sqlite3_column_int64(stmt, i); 1958 if (val > MAX_SAFE_INTEGER || val < MIN_SAFE_INTEGER) { 1959 JS_SetPropertyStr(ctx, target, colname, JS_NewBigInt64(ctx, val)); 1960 } else { 1961 JS_SetPropertyStr(ctx, target, colname, JS_NewInt64(ctx, val)); 1962 } 1963 break; 1964 } 1965 case SQLITE_FLOAT: { 1966 double val = sqlite3_column_double(stmt, i); 1967 JS_SetPropertyStr(ctx, target, colname, JS_NewFloat64(ctx, val)); 1968 break; 1969 } 1970 case SQLITE_BLOB: { 1971 JSValue abuf; 1972 const uint8_t *blobdata = sqlite3_column_blob(stmt, i); 1973 size_t bloblen = sqlite3_column_bytes(stmt, i); 1974 abuf = JS_NewArrayBufferCopy(ctx, blobdata, bloblen); 1975 JS_SetPropertyStr(ctx, target, colname, JS_NewTypedArraySimple(ctx, abuf, 1)); 1976 break; 1977 } 1978 case SQLITE_NULL: 1979 JS_SetPropertyStr(ctx, target, colname, JS_NULL); 1980 break; 1981 case SQLITE_TEXT: { 1982 const char *text = (const char *) sqlite3_column_text(stmt, i); 1983 JS_SetPropertyStr(ctx, target, colname, JS_NewString(ctx, text)); 1984 break; 1985 } 1986 default: 1987 JS_ThrowInternalError(ctx, "unexpected type from DB"); 1988 return -1; 1989 } 1990 } 1991 return 0; 1992 } 1993 1994 1995 static JSValue js_sqlite3_stmt_get_all(JSContext *ctx, JSValue this_val, 1996 int argc, JSValueConst *argv) 1997 { 1998 JSValue ret_val = JS_UNDEFINED; 1999 JSValue stmt_handle = argv[0]; 2000 sqlite3_stmt *stmt; 2001 sqlite3 *db; 2002 int sqlret; 2003 JSValue rows_array = JS_UNDEFINED; 2004 2005 stmt = JS_GetOpaque(stmt_handle, js_sqlite3_statement_class_id); 2006 if (!stmt) { 2007 ret_val = JS_ThrowTypeError(ctx, "invalid sqlite3 database handle"); 2008 goto done; 2009 } 2010 db = sqlite3_db_handle(stmt); 2011 sqlret = sqlite3_reset(stmt); 2012 if (SQLITE_OK != sqlret) { 2013 fprintf(stderr, "sqlite3_reset failed (in stmt_get_all): %s\n", sqlite3_errmsg(db)); 2014 ret_val = JS_ThrowTypeError(ctx, "failed to reset"); 2015 goto done; 2016 } 2017 sqlret = sqlite3_clear_bindings(stmt); 2018 if (SQLITE_OK != sqlret) { 2019 ret_val = JS_ThrowTypeError(ctx, "failed to clear bindings"); 2020 goto done; 2021 } 2022 if (argc > 1) { 2023 if (0 != bind_from_object(ctx, stmt, argv[1])) { 2024 ret_val = JS_EXCEPTION; 2025 goto done; 2026 } 2027 } 2028 rows_array = JS_NewArray(ctx); 2029 while (1) { 2030 sqlret = sqlite3_step(stmt); 2031 switch (sqlret) { 2032 case SQLITE_ROW: { 2033 JSValue row_obj = JS_NewObject(ctx); 2034 if (0 != extract_result_row(ctx, stmt, row_obj)) { 2035 goto fail; 2036 } 2037 qjs_array_append_new(ctx, rows_array, row_obj); 2038 break; 2039 } 2040 case SQLITE_DONE: { 2041 sqlret = sqlite3_reset(stmt); 2042 if (SQLITE_OK != sqlret) { 2043 fprintf(stderr, "sqlite3_reset failed (in stmt_get_all after SQLITE_DONE): %s\n", sqlite3_errmsg(db)); 2044 ret_val = JS_ThrowTypeError(ctx, "failed to reset"); 2045 } else { 2046 ret_val = JS_DupValue(ctx, rows_array); 2047 } 2048 goto done; 2049 } 2050 default: 2051 ret_val = throw_sqlite3_error(ctx, db); 2052 sqlite3_reset(stmt); 2053 goto done; 2054 } 2055 } 2056 done: 2057 JS_FreeValue(ctx, rows_array); 2058 return ret_val; 2059 fail: 2060 ret_val = JS_EXCEPTION; 2061 goto done; 2062 } 2063 2064 static JSValue js_sqlite3_stmt_get_first(JSContext *ctx, JSValue this_val, 2065 int argc, JSValueConst *argv) 2066 { 2067 JSValue ret_val = JS_UNDEFINED; 2068 JSValue stmt_handle = argv[0]; 2069 sqlite3_stmt *stmt; 2070 sqlite3 *db; 2071 int sqlret; 2072 2073 stmt = JS_GetOpaque(stmt_handle, js_sqlite3_statement_class_id); 2074 if (!stmt) { 2075 ret_val = JS_ThrowTypeError(ctx, "invalid sqlite3 database handle"); 2076 goto done; 2077 } 2078 db = sqlite3_db_handle(stmt); 2079 sqlret = sqlite3_reset(stmt); 2080 if (SQLITE_OK != sqlret) { 2081 fprintf(stderr, "sqlite3_reset failed (in stmt_get_first): %s\n", sqlite3_errmsg(db)); 2082 ret_val = JS_ThrowTypeError(ctx, "failed to reset"); 2083 goto done; 2084 } 2085 sqlret = sqlite3_clear_bindings(stmt); 2086 if (SQLITE_OK != sqlret) { 2087 ret_val = JS_ThrowTypeError(ctx, "failed to clear bindings"); 2088 goto done; 2089 } 2090 if (argc > 1) { 2091 if (0 != bind_from_object(ctx, stmt, argv[1])) { 2092 ret_val = JS_EXCEPTION; 2093 goto done; 2094 } 2095 } 2096 while (1) { 2097 sqlret = sqlite3_step(stmt); 2098 switch (sqlret) { 2099 case SQLITE_ROW: { 2100 JSValue row_obj = JS_NewObject(ctx); 2101 if (0 != extract_result_row(ctx, stmt, row_obj)) { 2102 goto fail; 2103 } 2104 ret_val = row_obj; 2105 goto done; 2106 } 2107 case SQLITE_DONE: { 2108 ret_val = JS_UNDEFINED; 2109 goto done; 2110 } 2111 default: 2112 ret_val = throw_sqlite3_error(ctx, db); 2113 goto done; 2114 } 2115 } 2116 reset: 2117 sqlret = sqlite3_reset(stmt); 2118 if (SQLITE_OK != sqlret) { 2119 fprintf(stderr, "sqlite3_reset failed (in stmt_get_first): %s\n", sqlite3_errmsg(db)); 2120 JS_FreeValue(ctx, ret_val); 2121 ret_val = JS_ThrowTypeError(ctx, "failed to reset"); 2122 } 2123 done: 2124 return ret_val; 2125 fail: 2126 ret_val = JS_EXCEPTION; 2127 goto done; 2128 } 2129 2130 2131 static const JSCFunctionListEntry tart_talercrypto_funcs[] = { 2132 JS_CFUNC_DEF("structuredClone", 1, js_structured_clone), 2133 JS_CFUNC_DEF("encodeUtf8", 1, js_encode_utf8), 2134 JS_CFUNC_DEF("crashForDebug", 0, js_crash_for_debug), 2135 JS_CFUNC_DEF("decodeUtf8", 1, js_decode_utf8), 2136 JS_CFUNC_DEF("randomBytes", 1, js_random_bytes), 2137 JS_CFUNC_DEF("encodeCrock", 1, js_talercrypto_encode_crock), 2138 JS_CFUNC_DEF("decodeCrock", 1, js_talercrypto_decode_crock), 2139 JS_CFUNC_DEF("hash", 1, js_talercrypto_hash), 2140 JS_CFUNC_DEF("hashStateInit", 0, js_talercrypto_hash_state_init), 2141 JS_CFUNC_DEF("hashStateUpdate", 2, js_talercrypto_hash_state_update), 2142 JS_CFUNC_DEF("hashStateFinish", 1, js_talercrypto_hash_state_finish), 2143 JS_CFUNC_DEF("hashArgon2id", 5, js_talercrypto_hash_argon2id), 2144 JS_CFUNC_DEF("eddsaGetPublic", 1, js_talercrypto_eddsa_key_get_public), 2145 JS_CFUNC_DEF("ecdheGetPublic", 1, js_talercrypto_ecdhe_key_get_public), 2146 JS_CFUNC_DEF("eddsaSign", 2, js_talercrypto_eddsa_sign), 2147 JS_CFUNC_DEF("eddsaVerify", 3, js_talercrypto_eddsa_verify), 2148 JS_CFUNC_DEF("kdf", 3, js_talercrypto_kdf), 2149 JS_CFUNC_DEF("keyExchangeEcdhEddsa", 2, js_talercrypto_kx_ecdh_eddsa), 2150 JS_CFUNC_DEF("keyExchangeEddsaEcdh", 2, js_talercrypto_kx_eddsa_ecdh), 2151 JS_CFUNC_DEF("rsaBlind", 3, js_talercrypto_rsa_blind), 2152 JS_CFUNC_DEF("rsaUnblind", 3, js_talercrypto_rsa_unblind), 2153 JS_CFUNC_DEF("rsaVerify", 3, js_talercrypto_rsa_verify), 2154 JS_CFUNC_DEF("sqlite3Open", 1, js_sqlite3_open), 2155 JS_CFUNC_DEF("sqlite3Close", 1, js_sqlite3_close), 2156 JS_CFUNC_DEF("sqlite3Prepare", 2, js_sqlite3_prepare), 2157 JS_CFUNC_DEF("sqlite3Finalize", 1, js_sqlite3_finalize), 2158 JS_CFUNC_DEF("sqlite3Exec", 2, js_sqlite3_exec), 2159 JS_CFUNC_DEF("sqlite3StmtRun", 2, js_sqlite3_stmt_run), 2160 JS_CFUNC_DEF("sqlite3StmtGetFirst", 2, js_sqlite3_stmt_get_first), 2161 JS_CFUNC_DEF("sqlite3StmtGetAll", 2, js_sqlite3_stmt_get_all), 2162 }; 2163 2164 static int tart_talercrypto_init(JSContext *ctx, JSModuleDef *m) 2165 { 2166 /* create the HashState class */ 2167 JS_NewClassID(&js_hash_state_class_id); 2168 JS_NewClass(JS_GetRuntime(ctx), js_hash_state_class_id, &js_hash_state_class); 2169 2170 /* create the Sqlite3Database class*/ 2171 JS_NewClassID(&js_sqlite3_database_class_id); 2172 JS_NewClass(JS_GetRuntime(ctx), js_sqlite3_database_class_id, &js_sqlite3_database_class); 2173 2174 /* create the Sqlite3Statement class*/ 2175 JS_NewClassID(&js_sqlite3_statement_class_id); 2176 JS_NewClass(JS_GetRuntime(ctx), js_sqlite3_statement_class_id, &js_sqlite3_statement_class); 2177 2178 return JS_SetModuleExportList(ctx, m, tart_talercrypto_funcs, 2179 countof(tart_talercrypto_funcs)); 2180 } 2181 2182 JSModuleDef *tart_init_module_talercrypto(JSContext *ctx, const char *module_name) 2183 { 2184 JSModuleDef *m; 2185 m = JS_NewCModule(ctx, module_name, tart_talercrypto_init); 2186 if (!m) { 2187 return NULL; 2188 } 2189 JS_AddModuleExportList(ctx, m, tart_talercrypto_funcs, 2190 countof(tart_talercrypto_funcs)); 2191 return m; 2192 }