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