static void suboption(void) { unsigned char subchar; printsub('<', subbuffer, SB_LEN()+2); switch (subchar = SB_GET()) { case TELOPT_TTYPE: if (my_want_state_is_wont(TELOPT_TTYPE)) return; if (SB_EOF() || SB_GET() != TELQUAL_SEND) { return; } else { const char *name; unsigned char temp[50]; int len; name = gettermname(); len = strlen(name) + 4 + 2; if (len < NETROOM()) { sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, TELQUAL_IS, name, IAC, SE); ring_supply_data(&netoring, temp, len); printsub('>', &temp[2], len-2); } else { ExitString("No room in buffer for terminal type.\n", 1); /*NOTREACHED*/ } } break; case TELOPT_TSPEED: if (my_want_state_is_wont(TELOPT_TSPEED)) return; if (SB_EOF()) return; if (SB_GET() == TELQUAL_SEND) { long ospeed, ispeed; unsigned char temp[50]; int len; TerminalSpeeds(&ispeed, &ospeed); sprintf((char *)temp, "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED, TELQUAL_IS, ospeed, ispeed, IAC, SE); len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ if (len < NETROOM()) { ring_supply_data(&netoring, temp, len); printsub('>', temp+2, len - 2); } /*@*/ else printf("lm_will: not enough room in buffer\n"); } break; case TELOPT_LFLOW: if (my_want_state_is_wont(TELOPT_LFLOW)) return; if (SB_EOF()) return; switch(SB_GET()) { case LFLOW_RESTART_ANY: restartany = 1; break; case LFLOW_RESTART_XON: restartany = 0; break; case LFLOW_ON: localflow = 1; break; case LFLOW_OFF: localflow = 0; break; default: return; } setcommandmode(); setconnmode(0); break; case TELOPT_LINEMODE: if (my_want_state_is_wont(TELOPT_LINEMODE)) return; if (SB_EOF()) return; switch (SB_GET()) { case WILL: lm_will(subpointer, SB_LEN()); break; case WONT: lm_wont(subpointer, SB_LEN()); break; case DO: lm_do(subpointer, SB_LEN()); break; case DONT: lm_dont(subpointer, SB_LEN()); break; case LM_SLC: slc(subpointer, SB_LEN()); break; case LM_MODE: lm_mode(subpointer, SB_LEN(), 0); break; default: break; } break; #ifdef OLD_ENVIRON case TELOPT_OLD_ENVIRON: #endif case TELOPT_NEW_ENVIRON: if (SB_EOF()) return; switch(SB_PEEK()) { case TELQUAL_IS: case TELQUAL_INFO: if (my_want_state_is_dont(subchar)) return; break; case TELQUAL_SEND: if (my_want_state_is_wont(subchar)) { return; } break; default: return; } env_opt(subpointer, SB_LEN()); break; case TELOPT_XDISPLOC: if (my_want_state_is_wont(TELOPT_XDISPLOC)) return; if (SB_EOF()) return; if (SB_GET() == TELQUAL_SEND) { unsigned char temp[50], *dp; int len; if ((dp = env_getvalue("DISPLAY")) == NULL || strlen(dp) > sizeof(temp) - 7) { /* * Something happened, we no longer have a DISPLAY * variable. Or it is too long. So, turn off the option. */ send_wont(TELOPT_XDISPLOC, 1); break; } snprintf(temp, sizeof(temp), "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE); len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ if (len < NETROOM()) { ring_supply_data(&netoring, temp, len); printsub('>', temp+2, len - 2); } /*@*/ else printf("lm_will: not enough room in buffer\n"); } break; #ifdef AUTHENTICATION case TELOPT_AUTHENTICATION: { if (!autologin) break; if (SB_EOF()) return; switch(SB_GET()) { case TELQUAL_IS: if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) return; auth_is(subpointer, SB_LEN()); break; case TELQUAL_SEND: if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) return; auth_send(subpointer, SB_LEN()); break; case TELQUAL_REPLY: if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) return; auth_reply(subpointer, SB_LEN()); break; case TELQUAL_NAME: if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) return; auth_name(subpointer, SB_LEN()); break; } } break; #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: if (SB_EOF()) return; switch(SB_GET()) { case ENCRYPT_START: if (my_want_state_is_dont(TELOPT_ENCRYPT)) return; encrypt_start(subpointer, SB_LEN()); break; case ENCRYPT_END: if (my_want_state_is_dont(TELOPT_ENCRYPT)) return; encrypt_end(); break; case ENCRYPT_SUPPORT: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; encrypt_support(subpointer, SB_LEN()); break; case ENCRYPT_REQSTART: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; encrypt_request_start(subpointer, SB_LEN()); break; case ENCRYPT_REQEND: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; /* * We can always send an REQEND so that we cannot * get stuck encrypting. We should only get this * if we have been able to get in the correct mode * anyhow. */ encrypt_request_end(); break; case ENCRYPT_IS: if (my_want_state_is_dont(TELOPT_ENCRYPT)) return; encrypt_is(subpointer, SB_LEN()); break; case ENCRYPT_REPLY: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; encrypt_reply(subpointer, SB_LEN()); break; case ENCRYPT_ENC_KEYID: if (my_want_state_is_dont(TELOPT_ENCRYPT)) return; encrypt_enc_keyid(subpointer, SB_LEN()); break; case ENCRYPT_DEC_KEYID: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; encrypt_dec_keyid(subpointer, SB_LEN()); break; default: break; } break; #endif /* ENCRYPTION */ default: break; } }
unsigned short btchip_apdu_get_trusted_input() { unsigned char apduLength; unsigned char dataOffset = 0; unsigned char trustedInputSignature[32]; cx_sha256_t hash; apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; SB_CHECK(N_btchip.bkp.config.operationMode); switch (SB_GET(N_btchip.bkp.config.operationMode)) { case BTCHIP_MODE_WALLET: case BTCHIP_MODE_RELAXED_WALLET: case BTCHIP_MODE_SERVER: break; default: return BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; } if (G_io_apdu_buffer[ISO_OFFSET_P1] == GET_TRUSTED_INPUT_P1_FIRST) { // Initialize btchip_context_D.transactionTargetInput = btchip_read_u32(G_io_apdu_buffer + ISO_OFFSET_CDATA, 1, 0); btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; btchip_context_D.trustedInputProcessed = 0; btchip_context_D.transactionContext.consumeP2SH = 0; btchip_set_check_internal_structure_integrity(1); dataOffset = 4; btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; btchip_context_D.usingSegwit = 0; } else if (G_io_apdu_buffer[ISO_OFFSET_P1] != GET_TRUSTED_INPUT_P1_NEXT) { return BTCHIP_SW_INCORRECT_P1_P2; } if (G_io_apdu_buffer[ISO_OFFSET_P2] != 0x00) { return BTCHIP_SW_INCORRECT_P1_P2; } btchip_context_D.transactionBufferPointer = G_io_apdu_buffer + ISO_OFFSET_CDATA + dataOffset; btchip_context_D.transactionDataRemaining = apduLength - dataOffset; transaction_parse(PARSE_MODE_TRUSTED_INPUT); if (btchip_context_D.transactionContext.transactionState == BTCHIP_TRANSACTION_PARSED) { unsigned char targetHash[32]; btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; btchip_set_check_internal_structure_integrity(1); if (!btchip_context_D.trustedInputProcessed) { // Output was not found return BTCHIP_SW_INCORRECT_DATA; } cx_hash(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, (unsigned char *)NULL, 0, targetHash, 32); // Otherwise prepare cx_rng(G_io_apdu_buffer, 8); G_io_apdu_buffer[0] = MAGIC_TRUSTED_INPUT; G_io_apdu_buffer[1] = 0x00; cx_sha256_init(&hash); cx_hash(&hash.header, CX_LAST, targetHash, 32, G_io_apdu_buffer + 4, 32); btchip_write_u32_le(G_io_apdu_buffer + 4 + 32, btchip_context_D.transactionTargetInput); os_memmove(G_io_apdu_buffer + 4 + 32 + 4, btchip_context_D.transactionContext.transactionAmount, 8); cx_hmac_sha256(N_btchip.bkp.trustedinput_key, sizeof(N_btchip.bkp.trustedinput_key), G_io_apdu_buffer, TRUSTEDINPUT_SIZE, trustedInputSignature, 32); os_memmove(G_io_apdu_buffer + TRUSTEDINPUT_SIZE, trustedInputSignature, 8); btchip_context_D.outLength = 0x38; } return BTCHIP_SW_OK; }
void transaction_parse(unsigned char parseMode) { unsigned char optionP2SHSkip2FA = ((N_btchip.bkp.config.options & BTCHIP_OPTION_SKIP_2FA_P2SH) != 0); btchip_set_check_internal_structure_integrity(0); BEGIN_TRY { TRY { for (;;) { switch (btchip_context_D.transactionContext.transactionState) { case BTCHIP_TRANSACTION_NONE: { PRINTF("Init transaction parser\n"); // Reset transaction state btchip_context_D.transactionContext .transactionRemainingInputsOutputs = 0; btchip_context_D.transactionContext .transactionCurrentInputOutput = 0; btchip_context_D.transactionContext.scriptRemaining = 0; os_memset( btchip_context_D.transactionContext.transactionAmount, 0, sizeof(btchip_context_D.transactionContext .transactionAmount)); // TODO : transactionControlFid // Reset hashes if (btchip_context_D.usingOverwinter) { if (btchip_context_D.segwitParsedOnce) { uint8_t parameters[16]; os_memmove(parameters, OVERWINTER_PARAM_SIGHASH, 16); btchip_write_u32_le(parameters + 12, btchip_context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING ? CONSENSUS_BRANCH_ID_SAPLING : CONSENSUS_BRANCH_ID_OVERWINTER); cx_blake2b_init2(&btchip_context_D.transactionHashFull.blake2b, 256, NULL, 0, parameters, 16); } } else { cx_sha256_init(&btchip_context_D.transactionHashFull.sha256); } cx_sha256_init( &btchip_context_D.transactionHashAuthorization); if (btchip_context_D.usingSegwit) { btchip_context_D.transactionHashOption = 0; if (!btchip_context_D.segwitParsedOnce) { if (btchip_context_D.usingOverwinter) { cx_blake2b_init2(&btchip_context_D.segwit.hash.hashPrevouts.blake2b, 256, NULL, 0, OVERWINTER_PARAM_PREVOUTS, 16); cx_blake2b_init2(&btchip_context_D.transactionHashFull.blake2b, 256, NULL, 0, OVERWINTER_PARAM_SEQUENCE, 16); } else { cx_sha256_init( &btchip_context_D.segwit.hash.hashPrevouts.sha256); } } else { PRINTF("Resume SegWit hash\n"); PRINTF("SEGWIT Version\n%.*H\n",sizeof(btchip_context_D.transactionVersion),btchip_context_D.transactionVersion); PRINTF("SEGWIT HashedPrevouts\n%.*H\n",sizeof(btchip_context_D.segwit.cache.hashedPrevouts),btchip_context_D.segwit.cache.hashedPrevouts); PRINTF("SEGWIT HashedSequence\n%.*H\n",sizeof(btchip_context_D.segwit.cache.hashedSequence),btchip_context_D.segwit.cache.hashedSequence); if (btchip_context_D.usingOverwinter) { cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.transactionVersion, sizeof(btchip_context_D.transactionVersion), NULL, 0); cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.nVersionGroupId, sizeof(btchip_context_D.nVersionGroupId), NULL, 0); cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.segwit.cache.hashedPrevouts, sizeof(btchip_context_D.segwit.cache.hashedPrevouts), NULL, 0); cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.segwit.cache.hashedSequence, sizeof(btchip_context_D.segwit.cache.hashedSequence), NULL, 0); cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.segwit.cache.hashedOutputs, sizeof(btchip_context_D.segwit.cache.hashedOutputs), NULL, 0); cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0); if (btchip_context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0); // sapling hashShieldedSpends cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0); // sapling hashShieldedOutputs } cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.nLockTime, sizeof(btchip_context_D.nLockTime), NULL, 0); cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.nExpiryHeight, sizeof(btchip_context_D.nExpiryHeight), NULL, 0); if (btchip_context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { unsigned char valueBalance[8]; os_memset(valueBalance, 0, sizeof(valueBalance)); cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, valueBalance, sizeof(valueBalance), NULL, 0); // sapling valueBalance } cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.sigHashType, sizeof(btchip_context_D.sigHashType), NULL, 0); } else { cx_hash( &btchip_context_D.transactionHashFull.sha256.header, 0, btchip_context_D.transactionVersion, sizeof(btchip_context_D.transactionVersion), NULL, 0); cx_hash( &btchip_context_D.transactionHashFull.sha256.header, 0, btchip_context_D.segwit.cache.hashedPrevouts, sizeof(btchip_context_D.segwit.cache .hashedPrevouts), NULL, 0); cx_hash( &btchip_context_D.transactionHashFull.sha256.header, 0, btchip_context_D.segwit.cache.hashedSequence, sizeof(btchip_context_D.segwit.cache .hashedSequence), NULL, 0); cx_hash(&btchip_context_D .transactionHashAuthorization.header, 0, (unsigned char *)&btchip_context_D .segwit.cache, sizeof(btchip_context_D.segwit.cache), NULL, 0); } } } // Parse the beginning of the transaction // Version check_transaction_available(4); os_memmove(btchip_context_D.transactionVersion, btchip_context_D.transactionBufferPointer, 4); transaction_offset_increase(4); if (btchip_context_D.usingOverwinter) { // nVersionGroupId check_transaction_available(4); os_memmove(btchip_context_D.nVersionGroupId, btchip_context_D.transactionBufferPointer, 4); transaction_offset_increase(4); } if (G_coin_config->flags & FLAG_PEERCOIN_SUPPORT) { if (btchip_context_D.coinFamily == BTCHIP_FAMILY_PEERCOIN) { // Timestamp check_transaction_available(4); transaction_offset_increase(4); } } // Number of inputs btchip_context_D.transactionContext .transactionRemainingInputsOutputs = transaction_get_varint(); PRINTF("Number of inputs : " DEBUG_LONG "\n",btchip_context_D.transactionContext.transactionRemainingInputsOutputs); // Ready to proceed btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; // no break is intentional } case BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT: { unsigned char trustedInputFlag = 1; PRINTF("Process input\n"); if (btchip_context_D.transactionContext .transactionRemainingInputsOutputs == 0) { // No more inputs to hash, move forward btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_INPUT_HASHING_DONE; continue; } if (btchip_context_D.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } // Proceed with the next input if (parseMode == PARSE_MODE_TRUSTED_INPUT) { check_transaction_available( 36); // prevout : 32 hash + 4 index transaction_offset_increase(36); } if (parseMode == PARSE_MODE_SIGNATURE) { unsigned char trustedInputLength; unsigned char trustedInput[0x38]; unsigned char amount[8]; unsigned char *savePointer; // Expect the trusted input flag and trusted input // length check_transaction_available(2); switch (*btchip_context_D.transactionBufferPointer) { case 0: if (btchip_context_D.usingSegwit) { PRINTF("Non trusted input used in segwit mode"); goto fail; } trustedInputFlag = 0; break; case 1: if (btchip_context_D.usingSegwit) { PRINTF("Trusted input used in segwit mode"); goto fail; } trustedInputFlag = 1; break; case 2: if (!btchip_context_D.usingSegwit) { PRINTF("Segwit input not used in segwit mode"); goto fail; } break; default: PRINTF("Invalid trusted input flag\n"); goto fail; } /* trustedInputLength = *(btchip_context_D.transactionBufferPointer + 1); if (trustedInputLength > sizeof(trustedInput)) { PRINTF("Trusted input too long\n"); goto fail; } */ if (btchip_context_D.usingSegwit) { transaction_offset_increase(1); check_transaction_available( 36); // prevout : 32 hash + 4 index if (!btchip_context_D.segwitParsedOnce) { if (btchip_context_D.usingOverwinter) { cx_hash(&btchip_context_D.segwit.hash.hashPrevouts.blake2b.header, 0, btchip_context_D.transactionBufferPointer, 36, NULL, 0); } else { cx_hash( &btchip_context_D.segwit.hash.hashPrevouts .sha256.header, 0, btchip_context_D.transactionBufferPointer, 36, NULL, 0); } transaction_offset_increase(36); check_transaction_available(8); // update amount btchip_swap_bytes( amount, btchip_context_D.transactionBufferPointer, 8); if (transaction_amount_add_be( btchip_context_D.transactionContext .transactionAmount, btchip_context_D.transactionContext .transactionAmount, amount)) { PRINTF("Overflow\n"); goto fail; } PRINTF("Adding amount\n%.*H\n",8,btchip_context_D.transactionBufferPointer); PRINTF("New amount\n%.*H\n",8,btchip_context_D.transactionContext.transactionAmount); transaction_offset_increase(8); } else { btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; transaction_offset_increase(36); btchip_context_D.transactionHashOption = 0; check_transaction_available(8); // save amount os_memmove( btchip_context_D.inputValue, btchip_context_D.transactionBufferPointer, 8); transaction_offset_increase(8); btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; } } else if (!trustedInputFlag) { // Only authorized in relaxed wallet and server // modes SB_CHECK(N_btchip.bkp.config.operationMode); switch (SB_GET(N_btchip.bkp.config.operationMode)) { case BTCHIP_MODE_WALLET: if (!optionP2SHSkip2FA) { PRINTF("Untrusted input not authorized\n"); goto fail; } break; case BTCHIP_MODE_RELAXED_WALLET: case BTCHIP_MODE_SERVER: break; default: PRINTF("Untrusted input not authorized\n"); goto fail; } btchip_context_D.transactionBufferPointer++; btchip_context_D.transactionDataRemaining--; check_transaction_available( 36); // prevout : 32 hash + 4 index transaction_offset_increase(36); PRINTF("Marking relaxed input\n"); btchip_context_D.transactionContext.relaxed = 1; /* PRINTF("Clearing P2SH consumption\n"); btchip_context_D.transactionContext.consumeP2SH = 0; */ } else { trustedInputLength = *( btchip_context_D.transactionBufferPointer + 1); if ((trustedInputLength > sizeof(trustedInput)) || (trustedInputLength < 8)) { PRINTF("Invalid trusted input size\n"); goto fail; } check_transaction_available(2 + trustedInputLength); cx_hmac_sha256( N_btchip.bkp.trustedinput_key, sizeof(N_btchip.bkp.trustedinput_key), btchip_context_D.transactionBufferPointer + 2, trustedInputLength - 8, trustedInput, trustedInputLength); if (btchip_secure_memcmp( trustedInput, btchip_context_D.transactionBufferPointer + 2 + trustedInputLength - 8, 8) != 0) { PRINTF("Invalid signature\n"); goto fail; } os_memmove( trustedInput, btchip_context_D.transactionBufferPointer + 2, trustedInputLength - 8); if (trustedInput[0] != MAGIC_TRUSTED_INPUT) { PRINTF("Failed to verify trusted input signature\n"); goto fail; } // Update the hash with prevout data savePointer = btchip_context_D.transactionBufferPointer; /* // Check if a P2SH script is used if ((trustedInput[1] & FLAG_TRUSTED_INPUT_P2SH) == 0) { PRINTF("Clearing P2SH consumption\n"); btchip_context_D.transactionContext.consumeP2SH = 0; } */ btchip_context_D.transactionBufferPointer = trustedInput + 4; PRINTF("Trusted input hash\n%.*H\n",36,btchip_context_D.transactionBufferPointer); transaction_offset(36); btchip_context_D.transactionBufferPointer = savePointer + (2 + trustedInputLength); btchip_context_D.transactionDataRemaining -= (2 + trustedInputLength); // Update the amount btchip_swap_bytes(amount, trustedInput + 40, 8); if (transaction_amount_add_be( btchip_context_D.transactionContext .transactionAmount, btchip_context_D.transactionContext .transactionAmount, amount)) { PRINTF("Overflow\n"); goto fail; } PRINTF("Adding amount\n%.*H\n",8,(trustedInput + 40)); PRINTF("New amount\n%.*H\n",8,btchip_context_D.transactionContext.transactionAmount); } if (!btchip_context_D.usingSegwit) { // Do not include the input script length + value in // the authentication hash btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; } } // Read the script length btchip_context_D.transactionContext.scriptRemaining = transaction_get_varint(); PRINTF("Script to read " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); if ((parseMode == PARSE_MODE_SIGNATURE) && !trustedInputFlag && !btchip_context_D.usingSegwit) { // Only proceeds if this is not to be signed - so length // should be null if (btchip_context_D.transactionContext .scriptRemaining != 0) { PRINTF("Request to sign relaxed input\n"); if (!optionP2SHSkip2FA) { goto fail; } } } // Move on btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT; // no break is intentional } case BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { unsigned char dataAvailable; PRINTF("Process input script, remaining " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); if (btchip_context_D.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } // Scan for P2SH consumption - huge shortcut, but fine // enough // Also usable in SegWit mode if (btchip_context_D.transactionContext.scriptRemaining == 1) { if (*btchip_context_D.transactionBufferPointer == OP_CHECKMULTISIG) { if (optionP2SHSkip2FA) { PRINTF("Marking P2SH consumption\n"); btchip_context_D.transactionContext .consumeP2SH = 1; } } else { // When using the P2SH shortcut, all inputs must use // P2SH PRINTF("Disabling P2SH consumption\n"); btchip_context_D.transactionContext.consumeP2SH = 0; } transaction_offset_increase(1); btchip_context_D.transactionContext.scriptRemaining--; } if (btchip_context_D.transactionContext.scriptRemaining == 0) { if (parseMode == PARSE_MODE_SIGNATURE) { if (!btchip_context_D.usingSegwit) { // Restore dual hash for signature + // authentication btchip_context_D.transactionHashOption = TRANSACTION_HASH_BOTH; } else { if (btchip_context_D.segwitParsedOnce) { // Append the saved value PRINTF("SEGWIT Add value\n%.*H\n",8,btchip_context_D.inputValue); if (btchip_context_D.usingOverwinter) { cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.inputValue, 8, NULL, 0); } else { cx_hash(&btchip_context_D .transactionHashFull.sha256.header, 0, btchip_context_D.inputValue, 8, NULL, 0); } } } } // Sequence check_transaction_available(4); if (btchip_context_D.usingSegwit && !btchip_context_D.segwitParsedOnce) { if (btchip_context_D.usingOverwinter) { cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.transactionBufferPointer, 4, NULL, 0); } else { cx_hash(&btchip_context_D.transactionHashFull .sha256.header, 0, btchip_context_D.transactionBufferPointer, 4, NULL, 0); } } transaction_offset_increase(4); // Move to next input btchip_context_D.transactionContext .transactionRemainingInputsOutputs--; btchip_context_D.transactionContext .transactionCurrentInputOutput++; btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; continue; } // Save the last script byte for the P2SH check dataAvailable = (btchip_context_D.transactionDataRemaining > btchip_context_D.transactionContext .scriptRemaining - 1 ? btchip_context_D.transactionContext .scriptRemaining - 1 : btchip_context_D.transactionDataRemaining); if (dataAvailable == 0) { goto ok; } transaction_offset_increase(dataAvailable); btchip_context_D.transactionContext.scriptRemaining -= dataAvailable; break; } case BTCHIP_TRANSACTION_INPUT_HASHING_DONE: { PRINTF("Input hashing done\n"); if (parseMode == PARSE_MODE_SIGNATURE) { // inputs have been prepared, stop the parsing here if (btchip_context_D.usingSegwit && !btchip_context_D.segwitParsedOnce) { unsigned char hashedPrevouts[32]; unsigned char hashedSequence[32]; // Flush the cache if (btchip_context_D.usingOverwinter) { cx_hash(&btchip_context_D.segwit.hash.hashPrevouts.blake2b.header, CX_LAST, hashedPrevouts, 0, hashedPrevouts, 32); cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, CX_LAST, hashedSequence, 0, hashedSequence, 32); } else { cx_hash(&btchip_context_D.segwit.hash.hashPrevouts .sha256.header, CX_LAST, hashedPrevouts, 0, hashedPrevouts, 32); cx_sha256_init( &btchip_context_D.segwit.hash.hashPrevouts.sha256); cx_hash(&btchip_context_D.segwit.hash.hashPrevouts .sha256.header, CX_LAST, hashedPrevouts, sizeof(hashedPrevouts), hashedPrevouts, 32); cx_hash(&btchip_context_D.transactionHashFull .sha256.header, CX_LAST, hashedSequence, 0, hashedSequence, 32); cx_sha256_init( &btchip_context_D.transactionHashFull.sha256); cx_hash(&btchip_context_D.transactionHashFull .sha256.header, CX_LAST, hashedSequence, sizeof(hashedSequence), hashedSequence, 32); } os_memmove( btchip_context_D.segwit.cache.hashedPrevouts, hashedPrevouts, sizeof(hashedPrevouts)); os_memmove( btchip_context_D.segwit.cache.hashedSequence, hashedSequence, sizeof(hashedSequence)); PRINTF("hashPrevout\n%.*H\n",32,btchip_context_D.segwit.cache.hashedPrevouts); PRINTF("hashSequence\n%.*H\n",32,btchip_context_D.segwit.cache.hashedSequence); } if (btchip_context_D.usingSegwit && btchip_context_D.segwitParsedOnce) { if (!btchip_context_D.usingOverwinter) { PRINTF("SEGWIT hashedOutputs\n%.*H\n",sizeof(btchip_context_D.segwit.cache.hashedOutputs),btchip_context_D.segwit.cache.hashedOutputs); cx_hash( &btchip_context_D.transactionHashFull.sha256.header, 0, btchip_context_D.segwit.cache.hashedOutputs, sizeof(btchip_context_D.segwit.cache .hashedOutputs), NULL, 0); } btchip_context_D.transactionContext .transactionState = BTCHIP_TRANSACTION_SIGN_READY; } else { btchip_context_D.transactionContext .transactionState = BTCHIP_TRANSACTION_PRESIGN_READY; if (btchip_context_D.usingOverwinter) { cx_blake2b_init2(&btchip_context_D.transactionHashFull.blake2b, 256, NULL, 0, OVERWINTER_PARAM_OUTPUTS, 16); } else if (btchip_context_D.usingSegwit) { cx_sha256_init(&btchip_context_D.transactionHashFull.sha256); } } continue; } if (btchip_context_D.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } // Number of outputs btchip_context_D.transactionContext .transactionRemainingInputsOutputs = transaction_get_varint(); btchip_context_D.transactionContext .transactionCurrentInputOutput = 0; PRINTF("Number of outputs : " DEBUG_LONG "\n", btchip_context_D.transactionContext .transactionRemainingInputsOutputs); // Ready to proceed btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; // no break is intentional } case BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT: { if (btchip_context_D.transactionContext .transactionRemainingInputsOutputs == 0) { // No more outputs to hash, move forward btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE; continue; } if (btchip_context_D.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } // Amount check_transaction_available(8); if ((parseMode == PARSE_MODE_TRUSTED_INPUT) && (btchip_context_D.transactionContext .transactionCurrentInputOutput == btchip_context_D.transactionTargetInput)) { // Save the amount os_memmove(btchip_context_D.transactionContext .transactionAmount, btchip_context_D.transactionBufferPointer, 8); btchip_context_D.trustedInputProcessed = 1; } transaction_offset_increase(8); // Read the script length btchip_context_D.transactionContext.scriptRemaining = transaction_get_varint(); PRINTF("Script to read " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); // Move on btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; // no break is intentional } case BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { unsigned char dataAvailable; PRINTF("Process output script, remaining " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); /* // Special check if consuming a P2SH script if (parseMode == PARSE_MODE_TRUSTED_INPUT) { // Assume the full input script is sent in a single APDU, then do the ghetto validation if ((btchip_context_D.transactionBufferPointer[0] == OP_HASH160) && (btchip_context_D.transactionBufferPointer[btchip_context_D.transactionDataRemaining - 1] == OP_EQUAL)) { PRINTF("Marking P2SH output\n"); btchip_context_D.transactionContext.consumeP2SH = 1; } } */ if (btchip_context_D.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } if (btchip_context_D.transactionContext.scriptRemaining == 0) { // Move to next output btchip_context_D.transactionContext .transactionRemainingInputsOutputs--; btchip_context_D.transactionContext .transactionCurrentInputOutput++; btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; continue; } dataAvailable = (btchip_context_D.transactionDataRemaining > btchip_context_D.transactionContext .scriptRemaining ? btchip_context_D.transactionContext .scriptRemaining : btchip_context_D.transactionDataRemaining); if (dataAvailable == 0) { goto ok; } transaction_offset_increase(dataAvailable); btchip_context_D.transactionContext.scriptRemaining -= dataAvailable; break; } case BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE: { PRINTF("Output hashing done\n"); if (btchip_context_D.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } // Locktime check_transaction_available(4); transaction_offset_increase(4); if (btchip_context_D.transactionDataRemaining == 0) { btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_PARSED; continue; } else { btchip_context_D.transactionHashOption = 0; btchip_context_D.transactionContext.scriptRemaining = transaction_get_varint(); btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_PROCESS_EXTRA; continue; } } case BTCHIP_TRANSACTION_PROCESS_EXTRA: { unsigned char dataAvailable; if (btchip_context_D.transactionContext.scriptRemaining == 0) { btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_PARSED; continue; } if (btchip_context_D.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } dataAvailable = (btchip_context_D.transactionDataRemaining > btchip_context_D.transactionContext .scriptRemaining ? btchip_context_D.transactionContext .scriptRemaining : btchip_context_D.transactionDataRemaining); if (dataAvailable == 0) { goto ok; } transaction_offset_increase(dataAvailable); btchip_context_D.transactionContext.scriptRemaining -= dataAvailable; break; } case BTCHIP_TRANSACTION_PARSED: { PRINTF("Transaction parsed\n"); goto ok; } case BTCHIP_TRANSACTION_PRESIGN_READY: { PRINTF("Presign ready\n"); goto ok; } case BTCHIP_TRANSACTION_SIGN_READY: { PRINTF("Sign ready\n"); goto ok; } } } fail: PRINTF("Transaction parse - fail\n"); THROW(EXCEPTION); ok : {} } CATCH_OTHER(e) { PRINTF("Transaction parse - surprise fail\n"); btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; btchip_set_check_internal_structure_integrity(1); THROW(e); } // before the finally to restore the surrounding context if an exception // is raised during finally FINALLY { btchip_set_check_internal_structure_integrity(1); } } END_TRY; }
* Look at the sub-option buffer, and try to be helpful to the other * side. * * Currently we recognize: * * Terminal type is * Linemode * Window size * Terminal speed */ void suboption(void) { int subchar; DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);}); subchar = SB_GET(); switch (subchar) { case TELOPT_TSPEED: { int xspeed, rspeed; if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */ break; settimer(tspeedsubopt); if (SB_EOF() || SB_GET() != TELQUAL_IS) return; xspeed = atoi((char *)subpointer); while (SB_GET() != ',' && !SB_EOF()); if (SB_EOF()) return; rspeed = atoi((char *)subpointer); clientstat(TELOPT_TSPEED, xspeed, rspeed);
static void suboption(void) { unsigned char subchar; printsub('<', subbuffer, SB_LEN()+2); switch (subchar = SB_GET()) { case TELOPT_TTYPE: if (my_want_state_is_wont(TELOPT_TTYPE)) return; if (SB_EOF() || SB_GET() != TELQUAL_SEND) { return; } else { char *name; unsigned char temp[50]; int len; name = gettermname(); len = strlen(name) + 4 + 2; if (len < NETROOM()) { snprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, TELQUAL_IS, name, IAC, SE); ring_supply_data(&netoring, temp, len); printsub('>', &temp[2], len-2); } else ExitString("No room in buffer for terminal type.\n", 1); } break; case TELOPT_TSPEED: if (my_want_state_is_wont(TELOPT_TSPEED)) return; if (SB_EOF()) return; if (SB_GET() == TELQUAL_SEND) { long ospeed, ispeed; unsigned char temp[50]; int len; TerminalSpeeds(&ispeed, &ospeed); snprintf((char *)temp, sizeof(temp), "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED, TELQUAL_IS, ospeed, ispeed, IAC, SE); len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ if (len < NETROOM()) { ring_supply_data(&netoring, temp, len); printsub('>', temp+2, len - 2); } /*@*/ else printf("lm_will: not enough room in buffer\n"); } break; case TELOPT_LFLOW: if (my_want_state_is_wont(TELOPT_LFLOW)) return; if (SB_EOF()) return; switch(SB_GET()) { case LFLOW_RESTART_ANY: restartany = 1; break; case LFLOW_RESTART_XON: restartany = 0; break; case LFLOW_ON: localflow = 1; break; case LFLOW_OFF: localflow = 0; break; default: return; } setcommandmode(); setconnmode(0); break; case TELOPT_LINEMODE: if (my_want_state_is_wont(TELOPT_LINEMODE)) return; if (SB_EOF()) return; switch (SB_GET()) { case WILL: lm_will(subpointer, SB_LEN()); break; case WONT: lm_wont(subpointer, SB_LEN()); break; case DO: lm_do(subpointer, SB_LEN()); break; case DONT: lm_dont(subpointer, SB_LEN()); break; case LM_SLC: slc(subpointer, SB_LEN()); break; case LM_MODE: lm_mode(subpointer, SB_LEN(), 0); break; default: break; } break; case TELOPT_NEW_ENVIRON: if (SB_EOF()) return; switch(SB_PEEK()) { case TELQUAL_IS: case TELQUAL_INFO: if (my_want_state_is_dont(subchar)) return; break; case TELQUAL_SEND: if (my_want_state_is_wont(subchar)) { return; } break; default: return; } env_opt(subpointer, SB_LEN()); break; case TELOPT_XDISPLOC: if (my_want_state_is_wont(TELOPT_XDISPLOC)) return; if (SB_EOF()) return; if (SB_GET() == TELQUAL_SEND) { unsigned char temp[50], *dp; int len; if ((dp = env_getvalue("DISPLAY", 0)) == NULL) { /* * Something happened, we no longer have a DISPLAY * variable. So, turn off the option. */ send_wont(TELOPT_XDISPLOC, 1); break; } snprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE); len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ if (len < NETROOM()) { ring_supply_data(&netoring, temp, len); printsub('>', temp+2, len - 2); } /*@*/ else printf("lm_will: not enough room in buffer\n"); } break; default: break; } }