From 27fb301b222d0e3239e284c0e4bd390165531390 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 4 Oct 2016 18:53:32 +0200 Subject: [PATCH] validate mp_buffer_info_t usage for cases where len==0 --- extmod/modtrezorcrypto/modtrezorcrypto-aes.h | 5 +++- .../modtrezorcrypto/modtrezorcrypto-bip39.h | 6 ++-- .../modtrezorcrypto/modtrezorcrypto-ed25519.h | 6 ++++ .../modtrezorcrypto-nist256p1.h | 6 ++++ .../modtrezorcrypto/modtrezorcrypto-pbkdf2.h | 7 +++++ .../modtrezorcrypto-ripemd160.h | 4 ++- .../modtrezorcrypto-secp256k1.h | 6 ++++ .../modtrezorcrypto/modtrezorcrypto-sha256.h | 4 ++- .../modtrezorcrypto-sha3-256.h | 4 ++- .../modtrezorcrypto-sha3-512.h | 4 ++- .../modtrezorcrypto/modtrezorcrypto-sha512.h | 4 ++- extmod/modtrezorcrypto/modtrezorcrypto-ssss.h | 3 ++ extmod/modtrezormsg/modtrezormsg-stmhal.h | 4 ++- extmod/modtrezormsg/modtrezormsg-unix.h | 4 +-- extmod/modtrezorui/modtrezorui-display.h | 29 ++++++++++++++----- src/tests/run_tests.sh | 7 ++++- 16 files changed, 84 insertions(+), 19 deletions(-) diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-aes.h b/extmod/modtrezorcrypto/modtrezorcrypto-aes.h index e032a57416..9f56b86dff 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-aes.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-aes.h @@ -90,9 +90,12 @@ STATIC mp_obj_t mod_TrezorCrypto_AES_make_new(const mp_obj_type_t *type, size_t STATIC mp_obj_t mod_TrezorCrypto_AES_update(mp_obj_t self, mp_obj_t data) { mp_buffer_info_t buf; mp_get_buffer_raise(data, &buf, MP_BUFFER_READ); - mp_obj_AES_t *o = MP_OBJ_TO_PTR(self); vstr_t vstr; vstr_init_len(&vstr, buf.len); + if (buf.len == 0) { + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); + } + mp_obj_AES_t *o = MP_OBJ_TO_PTR(self); switch (o->mode & AESModeMask) { case ECB: if (buf.len & (AES_BLOCK_SIZE - 1)) { diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-bip39.h b/extmod/modtrezorcrypto/modtrezorcrypto-bip39.h index 8c6e659a80..636aa2b05e 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-bip39.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-bip39.h @@ -62,7 +62,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_TrezorCrypto_Bip39_from_data_obj, mod_Trezo STATIC mp_obj_t mod_TrezorCrypto_Bip39_check(mp_obj_t self, mp_obj_t mnemonic) { mp_buffer_info_t text; mp_get_buffer_raise(mnemonic, &text, MP_BUFFER_READ); - return mnemonic_check(text.buf) ? mp_const_true : mp_const_false; + return (text.len > 0 && mnemonic_check(text.buf)) ? mp_const_true : mp_const_false; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_TrezorCrypto_Bip39_check_obj, mod_TrezorCrypto_Bip39_check); @@ -77,7 +77,9 @@ STATIC mp_obj_t mod_TrezorCrypto_Bip39_seed(mp_obj_t self, mp_obj_t mnemonic, mp mp_get_buffer_raise(passphrase, &phrase, MP_BUFFER_READ); vstr_t vstr; vstr_init_len(&vstr, 64); - mnemonic_to_seed(mnemo.buf, phrase.buf, (uint8_t *)vstr.buf, NULL); // no callback for now + const char *pmnemonic = mnemo.len > 0 ? mnemo.buf : ""; + const char *ppassphrase = phrase.len > 0 ? phrase.buf : ""; + mnemonic_to_seed(pmnemonic, ppassphrase, (uint8_t *)vstr.buf, NULL); // no callback for now return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_TrezorCrypto_Bip39_seed_obj, mod_TrezorCrypto_Bip39_seed); diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h b/extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h index 0a9ae59a89..b764cc1427 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h @@ -48,6 +48,9 @@ STATIC mp_obj_t mod_TrezorCrypto_Ed25519_sign(mp_obj_t self, mp_obj_t secret_key if (sk.len != 32) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid length of secret key")); } + if (msg.len == 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Empty data to sign")); + } ed25519_public_key pk; ed25519_publickey(*(const ed25519_secret_key *)sk.buf, pk); vstr_t vstr; @@ -73,6 +76,9 @@ STATIC mp_obj_t mod_TrezorCrypto_Ed25519_verify(size_t n_args, const mp_obj_t *a if (sig.len != 64) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid length of signature")); } + if (msg.len == 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Empty data to verify")); + } return (0 == ed25519_sign_open(msg.buf, msg.len, *(const ed25519_public_key *)pk.buf, *(const ed25519_signature *)sig.buf)) ? mp_const_true : mp_const_false; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorCrypto_Ed25519_verify_obj, 4, 4, mod_TrezorCrypto_Ed25519_verify); diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h b/extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h index 78467b112e..a6b8889c29 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h @@ -55,6 +55,9 @@ STATIC mp_obj_t mod_TrezorCrypto_Nist256p1_sign(mp_obj_t self, mp_obj_t secret_k if (sk.len != 32) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid length of secret key")); } + if (msg.len == 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Empty data to sign")); + } vstr_t vstr; vstr_init_len(&vstr, 65); uint8_t pby; @@ -82,6 +85,9 @@ STATIC mp_obj_t mod_TrezorCrypto_Nist256p1_verify(size_t n_args, const mp_obj_t if (sig.len != 65) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid length of signature")); } + if (msg.len == 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Empty data to verify")); + } return mp_obj_new_bool(0 == ecdsa_verify(&nist256p1, (const uint8_t *)pk.buf, (const uint8_t *)sig.buf, (const uint8_t *)msg.buf, msg.len)); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorCrypto_Nist256p1_verify_obj, 4, 4, mod_TrezorCrypto_Nist256p1_verify); diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-pbkdf2.h b/extmod/modtrezorcrypto/modtrezorcrypto-pbkdf2.h index 1608e22aba..6bc976a35d 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-pbkdf2.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-pbkdf2.h @@ -34,6 +34,13 @@ STATIC mp_obj_t mod_TrezorCrypto_Pbkdf2_make_new(const mp_obj_type_t *type, size mp_buffer_info_t salt; mp_get_buffer_raise(args[2], &salt, MP_BUFFER_READ); + if (password.len == 0) { + password.buf = ""; + } + if (salt.len == 0) { + salt.buf = ""; + } + o->prf = 0; if (prf.len == 11 && memcmp(prf.buf, "hmac-sha256", prf.len) == 0) { pbkdf2_hmac_sha256_Init(&(o->ctx256), password.buf, password.len, salt.buf, salt.len); diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-ripemd160.h b/extmod/modtrezorcrypto/modtrezorcrypto-ripemd160.h index bfae67dbca..5f88a0c858 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-ripemd160.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-ripemd160.h @@ -43,7 +43,9 @@ STATIC mp_obj_t mod_TrezorCrypto_Ripemd160_update(mp_obj_t self, mp_obj_t data) mp_obj_Ripemd160_t *o = MP_OBJ_TO_PTR(self); mp_buffer_info_t msg; mp_get_buffer_raise(data, &msg, MP_BUFFER_READ); - ripemd160_Update(&(o->ctx), msg.buf, msg.len); + if (msg.len > 0) { + ripemd160_Update(&(o->ctx), msg.buf, msg.len); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_TrezorCrypto_Ripemd160_update_obj, mod_TrezorCrypto_Ripemd160_update); diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h b/extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h index 2837688578..0603f2fcf6 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h @@ -55,6 +55,9 @@ STATIC mp_obj_t mod_TrezorCrypto_Secp256k1_sign(mp_obj_t self, mp_obj_t secret_k if (sk.len != 32) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid length of secret key")); } + if (msg.len == 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Empty data to sign")); + } vstr_t vstr; vstr_init_len(&vstr, 65); uint8_t pby; @@ -82,6 +85,9 @@ STATIC mp_obj_t mod_TrezorCrypto_Secp256k1_verify(size_t n_args, const mp_obj_t if (sig.len != 65) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid length of signature")); } + if (msg.len == 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Empty data to verify")); + } return mp_obj_new_bool(0 == ecdsa_verify(&secp256k1, (const uint8_t *)pk.buf, (const uint8_t *)sig.buf, (const uint8_t *)msg.buf, msg.len)); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorCrypto_Secp256k1_verify_obj, 4, 4, mod_TrezorCrypto_Secp256k1_verify); diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-sha256.h b/extmod/modtrezorcrypto/modtrezorcrypto-sha256.h index 9f2d1aec8e..4a5a4b52c4 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-sha256.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-sha256.h @@ -43,7 +43,9 @@ STATIC mp_obj_t mod_TrezorCrypto_Sha256_update(mp_obj_t self, mp_obj_t data) { mp_obj_Sha256_t *o = MP_OBJ_TO_PTR(self); mp_buffer_info_t msg; mp_get_buffer_raise(data, &msg, MP_BUFFER_READ); - sha256_Update(&(o->ctx), msg.buf, msg.len); + if (msg.len > 0) { + sha256_Update(&(o->ctx), msg.buf, msg.len); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_TrezorCrypto_Sha256_update_obj, mod_TrezorCrypto_Sha256_update); diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-sha3-256.h b/extmod/modtrezorcrypto/modtrezorcrypto-sha3-256.h index 6af4d6240e..2a4026cbb9 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-sha3-256.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-sha3-256.h @@ -43,7 +43,9 @@ STATIC mp_obj_t mod_TrezorCrypto_Sha3_256_update(mp_obj_t self, mp_obj_t data) { mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(self); mp_buffer_info_t msg; mp_get_buffer_raise(data, &msg, MP_BUFFER_READ); - sha3_Update(&(o->ctx), msg.buf, msg.len); + if (msg.len > 0) { + sha3_Update(&(o->ctx), msg.buf, msg.len); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_TrezorCrypto_Sha3_256_update_obj, mod_TrezorCrypto_Sha3_256_update); diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-sha3-512.h b/extmod/modtrezorcrypto/modtrezorcrypto-sha3-512.h index 68ced3ab60..0a66705a39 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-sha3-512.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-sha3-512.h @@ -43,7 +43,9 @@ STATIC mp_obj_t mod_TrezorCrypto_Sha3_512_update(mp_obj_t self, mp_obj_t data) { mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(self); mp_buffer_info_t msg; mp_get_buffer_raise(data, &msg, MP_BUFFER_READ); - sha3_Update(&(o->ctx), msg.buf, msg.len); + if (msg.len > 0) { + sha3_Update(&(o->ctx), msg.buf, msg.len); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_TrezorCrypto_Sha3_512_update_obj, mod_TrezorCrypto_Sha3_512_update); diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-sha512.h b/extmod/modtrezorcrypto/modtrezorcrypto-sha512.h index 3faf0279e4..8de24f4711 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-sha512.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-sha512.h @@ -42,7 +42,9 @@ STATIC mp_obj_t mod_TrezorCrypto_Sha512_update(mp_obj_t self, mp_obj_t data) { mp_obj_Sha512_t *o = MP_OBJ_TO_PTR(self); mp_buffer_info_t msg; mp_get_buffer_raise(data, &msg, MP_BUFFER_READ); - sha512_Update(&(o->ctx), msg.buf, msg.len); + if (msg.len > 0) { + sha512_Update(&(o->ctx), msg.buf, msg.len); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_TrezorCrypto_Sha512_update_obj, mod_TrezorCrypto_Sha512_update); diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-ssss.h b/extmod/modtrezorcrypto/modtrezorcrypto-ssss.h index 3b33e5116c..df5fc30010 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-ssss.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-ssss.h @@ -76,6 +76,9 @@ STATIC mp_obj_t mod_TrezorCrypto_SSSS_combine(mp_obj_t self, mp_obj_t shares) { if (MP_OBJ_IS_TYPE(share[i], &mp_type_bytes)) { mp_buffer_info_t s; mp_get_buffer_raise(share[i], &s, MP_BUFFER_READ); + if (s.len != 32) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Length of share has to be 256 bits")); + } bn_read_be(s.buf, &bnshares[n]); } else { memset(&bnshares[i], 0, sizeof(bignum256)); diff --git a/extmod/modtrezormsg/modtrezormsg-stmhal.h b/extmod/modtrezormsg/modtrezormsg-stmhal.h index 770b2ca5a6..4467b900ac 100644 --- a/extmod/modtrezormsg/modtrezormsg-stmhal.h +++ b/extmod/modtrezormsg/modtrezormsg-stmhal.h @@ -29,7 +29,9 @@ ssize_t msg_recv(uint8_t *iface, uint8_t *buf, size_t len) ssize_t msg_send(uint8_t iface, const uint8_t *buf, size_t len) { (void)iface; // ignore interface for now - USBD_HID_SendReport(&hUSBDDevice, (uint8_t *)buf, len); + if (len > 0) { + USBD_HID_SendReport(&hUSBDDevice, (uint8_t *)buf, len); + } return len; } diff --git a/extmod/modtrezormsg/modtrezormsg-unix.h b/extmod/modtrezormsg/modtrezormsg-unix.h index 6b7f238b08..9ac622d916 100644 --- a/extmod/modtrezormsg/modtrezormsg-unix.h +++ b/extmod/modtrezormsg/modtrezormsg-unix.h @@ -54,8 +54,8 @@ ssize_t msg_recv(uint8_t *iface, uint8_t *buf, size_t len) ssize_t msg_send(uint8_t iface, const uint8_t *buf, size_t len) { (void)iface; // ignore interface for UDP - ssize_t r = -1; - if (slen) { + ssize_t r = len; + if (slen > 0) { r = sendto(s, buf, len, MSG_DONTWAIT, (const struct sockaddr *)&si_other, slen); } return r; diff --git a/extmod/modtrezorui/modtrezorui-display.h b/extmod/modtrezorui/modtrezorui-display.h index a9b99c708a..2cd9feceb3 100644 --- a/extmod/modtrezorui/modtrezorui-display.h +++ b/extmod/modtrezorui/modtrezorui-display.h @@ -81,7 +81,9 @@ STATIC mp_obj_t mod_TrezorUi_Display_blit(size_t n_args, const mp_obj_t *args) { if (data.len != 2 * w * h) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Wrong data size (got %d bytes, expected %d bytes)", data.len, 2 * w * h)); } - display_blit(x, y, w, h, data.buf, data.len); + if (w > 0 && h > 0) { + display_blit(x, y, w, h, data.buf, data.len); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorUi_Display_blit_obj, 6, 6, mod_TrezorUi_Display_blit); @@ -157,7 +159,9 @@ STATIC mp_obj_t mod_TrezorUi_Display_text(size_t n_args, const mp_obj_t *args) { mp_int_t font = mp_obj_get_int(args[4]); mp_int_t fgcolor = mp_obj_get_int(args[5]); mp_int_t bgcolor = mp_obj_get_int(args[6]); - display_text(x, y, text.buf, text.len, font, fgcolor, bgcolor); + if (text.len > 0) { + display_text(x, y, text.buf, text.len, font, fgcolor, bgcolor); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorUi_Display_text_obj, 7, 7, mod_TrezorUi_Display_text); @@ -175,7 +179,9 @@ STATIC mp_obj_t mod_TrezorUi_Display_text_center(size_t n_args, const mp_obj_t * mp_int_t font = mp_obj_get_int(args[4]); mp_int_t fgcolor = mp_obj_get_int(args[5]); mp_int_t bgcolor = mp_obj_get_int(args[6]); - display_text_center(x, y, text.buf, text.len, font, fgcolor, bgcolor); + if (text.len > 0) { + display_text_center(x, y, text.buf, text.len, font, fgcolor, bgcolor); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorUi_Display_text_center_obj, 7, 7, mod_TrezorUi_Display_text_center); @@ -193,7 +199,9 @@ STATIC mp_obj_t mod_TrezorUi_Display_text_right(size_t n_args, const mp_obj_t *a mp_int_t font = mp_obj_get_int(args[4]); mp_int_t fgcolor = mp_obj_get_int(args[5]); mp_int_t bgcolor = mp_obj_get_int(args[6]); - display_text_right(x, y, text.buf, text.len, font, fgcolor, bgcolor); + if (text.len > 0) { + display_text_right(x, y, text.buf, text.len, font, fgcolor, bgcolor); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorUi_Display_text_right_obj, 7, 7, mod_TrezorUi_Display_text_right); @@ -206,7 +214,10 @@ STATIC mp_obj_t mod_TrezorUi_Display_text_width(mp_obj_t self, mp_obj_t text, mp mp_buffer_info_t txt; mp_get_buffer_raise(text, &txt, MP_BUFFER_READ); mp_int_t f = mp_obj_get_int(font); - uint32_t w = display_text_width(txt.buf, txt.len, f); + uint32_t w = 0; + if (txt.len > 0) { + w = display_text_width(txt.buf, txt.len, f); + } return MP_OBJ_NEW_SMALL_INT(w); } STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_TrezorUi_Display_text_width_obj, mod_TrezorUi_Display_text_width); @@ -225,7 +236,9 @@ STATIC mp_obj_t mod_TrezorUi_Display_qrcode(size_t n_args, const mp_obj_t *args) } mp_buffer_info_t data; mp_get_buffer_raise(args[3], &data, MP_BUFFER_READ); - display_qrcode(x, y, data.buf, data.len, scale); + if (data.len > 0) { + display_qrcode(x, y, data.buf, data.len, scale); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorUi_Display_qrcode_obj, 5, 5, mod_TrezorUi_Display_qrcode); @@ -320,7 +333,9 @@ STATIC mp_obj_t mod_TrezorUi_Display_raw(mp_obj_t self, mp_obj_t reg, mp_obj_t d mp_int_t r = mp_obj_get_int(reg); mp_buffer_info_t raw; mp_get_buffer_raise(data, &raw, MP_BUFFER_READ); - display_raw(r, raw.buf, raw.len); + if (raw.len > 0) { + display_raw(r, raw.buf, raw.len); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_TrezorUi_Display_raw_obj, mod_TrezorUi_Display_raw); diff --git a/src/tests/run_tests.sh b/src/tests/run_tests.sh index b29f4d1896..af36406eb0 100755 --- a/src/tests/run_tests.sh +++ b/src/tests/run_tests.sh @@ -1,7 +1,12 @@ #!/bin/bash results=() error=0 -for i in test_*.py; do +if [ -z "$1" ]; then + list="test_*.py" +else + list="$1" +fi +for i in $list; do echo if ../../vendor/micropython/unix/micropython $i; then results+=("OK $i")