void pivacy_cardemu_emulator::process_verify_pin(bytestring& c_apdu, bytestring& r_apdu) { if (c_apdu.size() < 5) { r_apdu = SW_LENGTH_ERROR; } else if ((c_apdu[OFS_P1] != 0x00) || ((c_apdu[OFS_P2] != 0x00) && (c_apdu[OFS_P2] != 0x01))) { ERROR_MSG("Invalid VERIFY PIN request"); r_apdu = SW_DATA_UNKNOWN; } else { bytestring supplied_PIN = c_apdu.substr(OFS_CDATA, c_apdu[OFS_LC]); if (c_apdu[OFS_P2] == 0x00) { if (supplied_PIN == user_PIN) { r_apdu = SW_OK; user_PIN_verified = true; } else { r_apdu = SW_PIN_INCORRECT; user_PIN_verified = false; } } else if (c_apdu[OFS_P2] == 0x01) { if (supplied_PIN == admin_PIN) { r_apdu = SW_OK; admin_PIN_verified = true; } else { r_apdu = SW_PIN_INCORRECT; admin_PIN_verified = false; } } } }
void pivacy_cardemu_emulator::process_select(bytestring& c_apdu, bytestring& r_apdu) { const bytestring IRMA_AID = "F849524D4163617264"; if (c_apdu.size() < 5) { r_apdu = SW_LENGTH_ERROR; } else if (c_apdu.substr(OFS_CDATA, c_apdu[OFS_LC]) != IRMA_AID) { r_apdu = SW_APPLICATION_UNKNOWN; } else { // Version 0.8 + emu // // Encoded as ISO7816 FCI record // // 0x6F YZ: FCI template (length: 0xYZ bytes) // 0xA5 YZ: Proprietary information encoded in BER-TLV (length: 0xYZ bytes) // 0x10 YZ: Sequence, version information (length: 0xYZ bytes) // 0x02 01: Integer, major (length: 0x01 byte) // 0x02 01: Integer, minor (length: 0x01 byte) // 0x02 01: Integer, maintenance (optional, length: 0x01 byte) // 0x02 01: Integer, build (optional, length: 0x01 byte) // 0x10 YZ: Sequence, extra information (optional, length: 0xYZ bytes) // 0x0C YZ: UTF-8 string, identifier (length: 0xYZ bytes) // 0x02 01: Integer, counter (optional, length: 0x01 byte) // 0x04 YZ: Octet string, data (optional, length: 0xYZ bytes) r_apdu = "6F11"; r_apdu += "A50F"; r_apdu += "100D"; r_apdu += "020100"; // major version = 0 r_apdu += "020108"; // minor version = 8 r_apdu += "1007"; r_apdu += "0C03454D55"; // EMU r_apdu += "9000"; } }
void pivacy_cardemu_emulator::process_prove_commitment(bytestring& c_apdu, bytestring& r_apdu) { if (!proof_started || !proof_have_context_and_D || (selected_credential == NULL)) { r_apdu = SW_WRONG_STATE; reset_proof(); } else if ((c_apdu.size() < 5) || (c_apdu[OFS_LC] != (SYSPAR(l_statzk) / 8))) { r_apdu = SW_LENGTH_ERROR; reset_proof(); } else if ((c_apdu[OFS_P1] != 0x00) || (c_apdu[OFS_P2] != 0x00)) { r_apdu = SW_DATA_UNKNOWN; reset_proof(); } else { // Retrieve the nonce bytestring nonce = c_apdu.substr(OFS_CDATA, c_apdu[OFS_LC]); // Generate the proof silvia_prover prover(selected_credential->get_issuer_public_key(), selected_credential->get_silvia_credential()); mpz_class c; mpz_class A_prime; mpz_class e_hat; mpz_class v_prime_hat; std::vector<mpz_class> a_i_hat; std::vector<silvia_attribute*> a_i; prover.prove(curproof_D, nonce.mpz_val(), curproof_context.mpz_val(), c, A_prime, e_hat, v_prime_hat, a_i_hat, a_i); // Save proof output std::vector<mpz_class>::iterator a_i_hat_it = a_i_hat.begin(); std::vector<silvia_attribute*>::iterator a_i_it = a_i.begin(); curproof_A_prime = bytestring(A_prime); curproof_e_hat = bytestring(e_hat); curproof_v_prime_hat = bytestring(v_prime_hat); /* Add hidden master secret */ curproof_attributes.push_back(bytestring(*a_i_hat_it)); a_i_hat_it++; for (std::vector<bool>::iterator i = curproof_D.begin(); i != curproof_D.end(); i++) { if ((*i) == true) { curproof_attributes.push_back(bytestring((*a_i_it)->rep())); a_i_it++; } else { curproof_attributes.push_back(bytestring(*a_i_hat_it)); a_i_hat_it++; } } // Return c r_apdu = bytestring(c); r_apdu += SW_OK; proof_proved = true; } }
void pivacy_cardemu_emulator::process_prove_credential(bytestring& c_apdu, bytestring& r_apdu) { reset_proof(); if ((c_apdu.size() < 5) || (c_apdu[OFS_LC] != 0x28)) { r_apdu = SW_LENGTH_ERROR; } else if ((c_apdu[OFS_P1] != 0x00) || (c_apdu[OFS_P2] != 0x00)) { r_apdu = SW_WRONG_STATE; } else { unsigned short credential_id = (c_apdu[OFS_CDATA] >> 8) + c_apdu[OFS_CDATA + 1]; /* Check if this credential exists */ selected_credential = NULL; for (std::vector<pivacy_credential*>::iterator i = credentials.begin(); i != credentials.end(); i++) { if ((*i)->get_credential_id() == credential_id) { selected_credential = *i; } } if (selected_credential == NULL) { ERROR_MSG("Attempt to start proof for non-existent credential 0x%04X", credential_id); r_apdu = SW_CREDENTIAL_UNKNOWN; } else { unsigned short D_val = (c_apdu[OFS_CDATA + 2] << 8) + c_apdu[OFS_CDATA + 2 + 1]; curproof_context = c_apdu.substr(OFS_CDATA + 2 + 2, SYSPAR(l_H) / 8); time_t timestamp = (c_apdu[OFS_CDATA + 2 + (SYSPAR(l_H) / 8) + 2] << 24) + (c_apdu[OFS_CDATA + 2 + (SYSPAR(l_H) / 8) + 3] << 16) + (c_apdu[OFS_CDATA + 2 + (SYSPAR(l_H) / 8) + 4] << 8) + (c_apdu[OFS_CDATA + 2 + (SYSPAR(l_H) / 8) + 5]); INFO_MSG("Started proof with context = %s, D = 0x%04X, timestamp = %d", curproof_context.hex_str().c_str(), D_val, timestamp); /* Convert D to vector of booleans, start at "expiry" */ unsigned short D_mask = 0x0002; std::vector<const char*> display_attributes; for (int i = 0; i < selected_credential->get_silvia_credential()->num_attributes(); i++) { if (FLAG_SET(D_val, D_mask)) { curproof_D.push_back(true); INFO_MSG("Revealing attribute %s", selected_credential->get_attribute_names()[i].c_str()); display_attributes.push_back(selected_credential->get_attribute_names()[i].c_str()); } else { curproof_D.push_back(false); INFO_MSG("Keeping attribute %s hidden", selected_credential->get_attribute_names()[i].c_str()); } D_mask <<= 1; } r_apdu = SW_OK; proof_started = true; proof_have_context_and_D = true; if (ui_connected) { int consent_result; pivacy_rv rv; if (((rv = pivacy_ui_consent("This terminal", &display_attributes[0], display_attributes.size(), 0, &consent_result) != PRV_OK) || ((rv = pivacy_ui_show_status(PIVACY_STATE_PRESENT)) != PRV_OK)) && !ui_optional) { reset_proof(); r_apdu = SW_UNKNOWN_ERROR; } if (rv == PRV_OK) { if (consent_result == PIVACY_CONSENT_NO) { reset_proof(); r_apdu = SW_SECURITY_STATUS_NOT_SATISFIED; } } } } } }