#define LOG_MODULE "ezusb-emu-node-sec-plug" #include #include "ezusb-emu/node-eeprom.h" #include "ezusb-emu/node-security-mem.h" #include "ezusb-emu/node-security-plug.h" #include "ezusb-iidx/secplug-cmd.h" #include "security/rp.h" #include "security/rp2.h" #include "security/util.h" #include "util/log.h" static struct security_mcode ezusb_iidx_emu_node_security_plug_boot_version; static uint32_t ezusb_iidx_emu_node_security_plug_boot_seeds[3]; static struct security_rp_sign_key ezusb_iidx_emu_node_security_plug_black_sign_key; static struct security_rp_sign_key ezusb_iidx_emu_node_security_plug_white_sign_key; static struct security_mcode ezusb_iidx_emu_node_security_plug_black_mcode; static struct security_mcode ezusb_iidx_emu_node_security_plug_white_mcode; static struct security_id ezusb_iidx_emu_node_security_plug_pcbid; static struct security_id ezusb_iidx_emu_node_security_plug_eamid; static enum ezusb_iidx_secplug_dongle_slot ezusb_iidx_emu_node_security_plug_active_dongle_slot; static enum ezusb_iidx_secplug_dongle_memory ezusb_iidx_emu_node_security_plug_active_dongle_mem; static uint8_t ezusb_iidx_emu_node_security_plug_enc_rom_data_seed; static void ezusb_iidx_emu_node_security_plug_encrypt_rom_data( uint8_t *buffer, uint8_t length); /* ------------------------------------------------------------------------- */ void ezusb_iidx_emu_node_security_plug_set_boot_version( const struct security_mcode *boot_version) { char *tmp; log_assert(boot_version); tmp = security_mcode_to_str(boot_version); log_misc("boot version: %s", tmp); free(tmp); memcpy( &ezusb_iidx_emu_node_security_plug_boot_version, boot_version, sizeof(struct security_mcode)); } void ezusb_iidx_emu_node_security_plug_set_boot_seeds(const uint32_t *seeds) { log_assert(seeds); log_misc("boot seeds: %d %d %d", seeds[0], seeds[1], seeds[2]); memcpy( &ezusb_iidx_emu_node_security_plug_boot_seeds, seeds, sizeof(ezusb_iidx_emu_node_security_plug_boot_seeds)); } void ezusb_iidx_emu_node_security_plug_set_plug_black_sign_key( const struct security_rp_sign_key *sign_key) { log_misc("black sign key: %s", sign_key->data); memcpy( &ezusb_iidx_emu_node_security_plug_black_sign_key, sign_key, sizeof(struct security_rp_sign_key)); } void ezusb_iidx_emu_node_security_plug_set_plug_white_sign_key( const struct security_rp_sign_key *sign_key) { log_misc("white sign key: %s", sign_key->data); memcpy( &ezusb_iidx_emu_node_security_plug_white_sign_key, sign_key, sizeof(struct security_rp_sign_key)); } void ezusb_iidx_emu_node_security_plug_set_plug_black_mcode( const struct security_mcode *mcode) { char *tmp; log_assert(mcode); tmp = security_mcode_to_str(mcode); log_misc("black mcode: %s", tmp); free(tmp); memcpy( &ezusb_iidx_emu_node_security_plug_black_mcode, mcode, sizeof(struct security_mcode)); } void ezusb_iidx_emu_node_security_plug_set_plug_white_mcode( const struct security_mcode *mcode) { char *tmp; log_assert(mcode); tmp = security_mcode_to_str(mcode); log_misc("white mcode: %s", tmp); free(tmp); memcpy( &ezusb_iidx_emu_node_security_plug_white_mcode, mcode, sizeof(struct security_mcode)); } void ezusb_iidx_emu_node_security_plug_set_pcbid( const struct security_id *pcbid) { char *tmp; tmp = security_id_to_str(pcbid, false); log_misc("PCBID: %s", tmp); free(tmp); memcpy( &ezusb_iidx_emu_node_security_plug_pcbid, pcbid, sizeof(struct security_id)); } void ezusb_iidx_emu_node_security_plug_set_eamid( const struct security_id *eamid) { char *tmp; tmp = security_id_to_str(eamid, false); log_misc("EAMID: %s", tmp); free(tmp); memcpy( &ezusb_iidx_emu_node_security_plug_eamid, eamid, sizeof(struct security_id)); } /* ------------------------------------------------------------- */ uint8_t ezusb_iidx_emu_node_security_plug_process_cmd_v1( uint8_t cmd_id, uint8_t cmd_data, uint8_t cmd_data2) { switch (cmd_id) { case EZUSB_IIDX_SECPLUG_CMD_V1_READ_ROM: log_misc("EZUSB_IIDX_SECPLUG_CMD_V1_READ_ROM"); ezusb_iidx_emu_node_security_plug_active_dongle_mem = EZUSB_IIDX_SECPLUG_DONGLE_MEM_ROM; ezusb_iidx_emu_node_security_plug_enc_rom_data_seed = cmd_data; return EZUSB_IIDX_SECPLUG_CMD_STATUS_V1_OK; case EZUSB_IIDX_SECPLUG_CMD_V1_READ_DATA: log_misc("EZUSB_IIDX_SECPLUG_CMD_V1_READ_DATA"); ezusb_iidx_emu_node_security_plug_active_dongle_mem = EZUSB_IIDX_SECPLUG_DONGLE_MEM_DATA; return EZUSB_IIDX_SECPLUG_CMD_STATUS_V1_OK; case EZUSB_IIDX_SECPLUG_CMD_V1_WRITE_DATA: log_misc("EZUSB_IIDX_SECPLUG_CMD_V1_WRITE_DATA"); /* TODO ? */ return EZUSB_IIDX_SECPLUG_CMD_STATUS_V1_OK; // Black dongle case EZUSB_IIDX_SECPLUG_CMD_V1_SELECT_DONGLE_1: log_misc("EZUSB_IIDX_SECPLUG_CMD_V1_SELECT_DONGLE_1"); ezusb_iidx_emu_node_security_plug_active_dongle_slot = EZUSB_IIDX_SECPLUG_DONGLE_SLOT_BLACK; return EZUSB_IIDX_SECPLUG_CMD_STATUS_V1_OK; // Used by D01 to also address black dongle? // Note that iidx 9 to 13 never had a white dongle // The white dongle/separate eamuse license key was introduced // with iidx 14 case EZUSB_IIDX_SECPLUG_CMD_V1_SELECT_DONGLE_2: log_misc("EZUSB_IIDX_SECPLUG_CMD_V1_SELECT_DONGLE_2"); ezusb_iidx_emu_node_security_plug_active_dongle_slot = EZUSB_IIDX_SECPLUG_DONGLE_SLOT_BLACK; return EZUSB_IIDX_SECPLUG_CMD_STATUS_V1_OK; default: log_warning("Unrecognised security plug v1 command: %02x", cmd_id); return EZUSB_IIDX_SECPLUG_CMD_STATUS_V1_FAULT; } } uint8_t ezusb_iidx_emu_node_security_plug_process_cmd_v2( uint8_t cmd_id, uint8_t cmd_data, uint8_t cmd_data2) { switch (cmd_id) { case EZUSB_IIDX_SECPLUG_CMD_V2_SEARCH: log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_SEARCH"); ezusb_iidx_emu_node_security_plug_active_dongle_mem = EZUSB_IIDX_SECPLUG_DONGLE_MEM_ROM; ezusb_iidx_emu_node_security_plug_enc_rom_data_seed = cmd_data; return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_SEARCH_OK; case EZUSB_IIDX_SECPLUG_CMD_V2_READ_DATA: log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_READ_DATA"); ezusb_iidx_emu_node_security_plug_active_dongle_mem = EZUSB_IIDX_SECPLUG_DONGLE_MEM_DATA; return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_READ_DATA_OK; case EZUSB_IIDX_SECPLUG_CMD_V2_READ_ROM: log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_READ_ROM"); ezusb_iidx_emu_node_security_plug_active_dongle_mem = EZUSB_IIDX_SECPLUG_DONGLE_MEM_ROM; ezusb_iidx_emu_node_security_plug_enc_rom_data_seed = cmd_data; return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_READ_ROM_OK; // pop'n music only ever uses slot 2 (white) and slot 4 (black). // If the configuration does not match then it will error out. // IIDX uses slots 2 and 3 and detects what is plugged into each slot so // ordering isn't important. IIDX also reads slot 1's data section but // doesn't care what dongle it is? case EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_1: log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_1"); ezusb_iidx_emu_node_security_plug_active_dongle_slot = EZUSB_IIDX_SECPLUG_DONGLE_SLOT_WHITE; return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_SECURITY_SEL_OK; case EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_2: log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_2"); ezusb_iidx_emu_node_security_plug_active_dongle_slot = EZUSB_IIDX_SECPLUG_DONGLE_SLOT_WHITE; return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_SECURITY_SEL_OK; case EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_3: log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_3"); ezusb_iidx_emu_node_security_plug_active_dongle_slot = EZUSB_IIDX_SECPLUG_DONGLE_SLOT_BLACK; return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_SECURITY_SEL_OK; case EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_4: log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_4"); ezusb_iidx_emu_node_security_plug_active_dongle_slot = EZUSB_IIDX_SECPLUG_DONGLE_SLOT_BLACK; return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_SECURITY_SEL_OK; case EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_5: log_misc("EZUSB_IIDX_SECPLUG_CMD_V2_SELECT_DONGLE_5"); // Unknown, not encountered during testing ezusb_iidx_emu_node_security_plug_active_dongle_slot = EZUSB_IIDX_SECPLUG_DONGLE_SLOT_WHITE; return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_SECURITY_SEL_OK; default: log_warning("Unrecognised security plug v2 command: %02x", cmd_id); return EZUSB_IIDX_SECPLUG_CMD_STATUS_V2_FAIL; } } bool ezusb_iidx_emu_node_security_plug_read_packet_v1( struct ezusb_iidx_msg_bulk_packet *pkg) { char *tmp; memset(pkg, 0x00, sizeof(struct ezusb_iidx_msg_bulk_packet)); if (ezusb_iidx_emu_node_security_plug_active_dongle_slot == EZUSB_IIDX_SECPLUG_DONGLE_SLOT_BLACK && ezusb_iidx_emu_node_security_plug_active_dongle_mem == EZUSB_IIDX_SECPLUG_DONGLE_MEM_ROM) { tmp = security_id_to_str(&ezusb_iidx_emu_node_security_plug_pcbid, false); log_misc("Reading security plug v1 black rom, PCBID %s", tmp); free(tmp); if (!security_id_verify(&ezusb_iidx_emu_node_security_plug_pcbid)) { log_fatal("PCBID verification failed"); return false; } pkg->node = 0x11; pkg->page = 0x00; memcpy( pkg->payload, &ezusb_iidx_emu_node_security_plug_pcbid, sizeof(struct security_id)); ezusb_iidx_emu_node_security_plug_encrypt_rom_data(pkg->payload, 10); } else if ( ezusb_iidx_emu_node_security_plug_active_dongle_slot == EZUSB_IIDX_SECPLUG_DONGLE_SLOT_BLACK && ezusb_iidx_emu_node_security_plug_active_dongle_mem == EZUSB_IIDX_SECPLUG_DONGLE_MEM_DATA) { log_misc("Reading security plug v1 black data"); pkg->node = 0x12; pkg->page = 0x00; security_rp_generate_signed_eeprom_data( &ezusb_iidx_emu_node_security_plug_boot_version, ezusb_iidx_emu_node_security_plug_boot_seeds, &ezusb_iidx_emu_node_security_plug_black_mcode, &ezusb_iidx_emu_node_security_plug_pcbid, (struct security_rp_eeprom *) pkg->payload); /* the signed test vector will be compared to the eeprom contents write test vector to eeprom to pass checks */ ezusb_iidx_emu_node_eeprom_write_memory(pkg->payload, 6, 6); } else if ( ezusb_iidx_emu_node_security_plug_active_dongle_slot == EZUSB_IIDX_SECPLUG_DONGLE_SLOT_WHITE && ezusb_iidx_emu_node_security_plug_active_dongle_mem == EZUSB_IIDX_SECPLUG_DONGLE_MEM_ROM) { tmp = security_id_to_str(&ezusb_iidx_emu_node_security_plug_eamid, false); log_misc("Reading security plug v1 white rom, EAMID %s", tmp); free(tmp); if (!security_id_verify(&ezusb_iidx_emu_node_security_plug_eamid)) { log_fatal("EAMID verification failed"); return false; } pkg->node = 0x11; pkg->page = 0x00; memcpy( pkg->payload, &ezusb_iidx_emu_node_security_plug_eamid, sizeof(struct security_id)); ezusb_iidx_emu_node_security_plug_encrypt_rom_data(pkg->payload, 10); } else if ( ezusb_iidx_emu_node_security_plug_active_dongle_slot == EZUSB_IIDX_SECPLUG_DONGLE_SLOT_WHITE && ezusb_iidx_emu_node_security_plug_active_dongle_mem == EZUSB_IIDX_SECPLUG_DONGLE_MEM_DATA) { log_misc("Reading security plug v1 white data"); pkg->node = 0x12; pkg->page = 0x00; security_rp_generate_signed_eeprom_data( &ezusb_iidx_emu_node_security_plug_boot_version, ezusb_iidx_emu_node_security_plug_boot_seeds, &ezusb_iidx_emu_node_security_plug_white_mcode, &ezusb_iidx_emu_node_security_plug_eamid, (struct security_rp_eeprom *) pkg->payload); /* XXX position 0 not verified, guess the test vector will be compared against eeprom contents write test vector to eeprom to pass checks */ ezusb_iidx_emu_node_eeprom_write_memory(pkg->payload, 0, 6); } else { log_warning("Invalid security plug v1 read"); return false; } return true; } bool ezusb_iidx_emu_node_security_plug_read_packet_v2( struct ezusb_iidx_msg_bulk_packet *pkg) { char *tmp; log_misc("Reading security plug v2 packet"); memset(pkg, 0x00, sizeof(struct ezusb_iidx_msg_bulk_packet)); if (ezusb_iidx_emu_node_security_plug_active_dongle_slot == EZUSB_IIDX_SECPLUG_DONGLE_SLOT_BLACK && ezusb_iidx_emu_node_security_plug_active_dongle_mem == EZUSB_IIDX_SECPLUG_DONGLE_MEM_ROM) { tmp = security_id_to_str(&ezusb_iidx_emu_node_security_plug_pcbid, false); log_misc("Reading security plug v2 black rom, PCBID %s", tmp); free(tmp); if (!security_id_verify(&ezusb_iidx_emu_node_security_plug_pcbid)) { log_fatal("PCBID verification failed"); return false; } pkg->node = 0x11; pkg->page = 0x00; memcpy( pkg->payload, &ezusb_iidx_emu_node_security_plug_pcbid, sizeof(struct security_id)); ezusb_iidx_emu_node_security_plug_encrypt_rom_data(pkg->payload, 10); } else if ( ezusb_iidx_emu_node_security_plug_active_dongle_slot == EZUSB_IIDX_SECPLUG_DONGLE_SLOT_BLACK && ezusb_iidx_emu_node_security_plug_active_dongle_mem == EZUSB_IIDX_SECPLUG_DONGLE_MEM_DATA) { log_misc("Reading security plug v2 black data"); pkg->node = 0x12; pkg->page = 0x00; security_rp2_generate_signed_eeprom_data( SECURITY_RP_UTIL_RP_TYPE_BLACK, &ezusb_iidx_emu_node_security_plug_black_sign_key, &ezusb_iidx_emu_node_security_plug_black_mcode, &ezusb_iidx_emu_node_security_plug_pcbid, (struct security_rp2_eeprom *) pkg->payload); } else if ( ezusb_iidx_emu_node_security_plug_active_dongle_slot == EZUSB_IIDX_SECPLUG_DONGLE_SLOT_WHITE && ezusb_iidx_emu_node_security_plug_active_dongle_mem == EZUSB_IIDX_SECPLUG_DONGLE_MEM_ROM) { tmp = security_id_to_str(&ezusb_iidx_emu_node_security_plug_eamid, false); log_misc("Reading security plug v2 white rom, EAMID %s", tmp); free(tmp); if (!security_id_verify(&ezusb_iidx_emu_node_security_plug_eamid)) { log_fatal("EAMID verification failed"); return false; } pkg->node = 0x11; pkg->page = 0x00; memcpy( pkg->payload, &ezusb_iidx_emu_node_security_plug_eamid, sizeof(struct security_id)); ezusb_iidx_emu_node_security_plug_encrypt_rom_data(pkg->payload, 10); } else if ( ezusb_iidx_emu_node_security_plug_active_dongle_slot == EZUSB_IIDX_SECPLUG_DONGLE_SLOT_WHITE && ezusb_iidx_emu_node_security_plug_active_dongle_mem == EZUSB_IIDX_SECPLUG_DONGLE_MEM_DATA) { log_misc("Reading security plug v2 white data"); pkg->node = 0x12; pkg->page = 0x00; security_rp2_generate_signed_eeprom_data( SECURITY_RP_UTIL_RP_TYPE_WHITE, &ezusb_iidx_emu_node_security_plug_white_sign_key, &ezusb_iidx_emu_node_security_plug_white_mcode, &ezusb_iidx_emu_node_security_plug_eamid, (struct security_rp2_eeprom *) pkg->payload); } return true; } bool ezusb_iidx_emu_node_security_plug_write_packet( const struct ezusb_iidx_msg_bulk_packet *pkg) { log_misc("Writing security plug packet"); return true; } /* ------------------------------------------------------------- */ static void ezusb_iidx_emu_node_security_plug_encrypt_rom_data( uint8_t *buffer, uint8_t length) { uint8_t data; for (int i = 0; i < length; i++) { data = ezusb_iidx_emu_node_security_mem_read_memory( (ezusb_iidx_emu_node_security_plug_enc_rom_data_seed + i) & 0xFF); /* log_misc("Encrypting %02X, seed %02X with sec mem lookup %02X", buffer[i], ezusb_iidx_emu_node_security_plug_enc_rom_data_seed, data); */ buffer[i] ^= data; } }