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