quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

tart_module.c (59865B)


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