void print_timestamp_irma(std::string msg, bytestring timestamp) { time_t expires; if (timestamp[IRMA_VERIFIER_METADATA_OFFSET] != 0x00) { // Check metadata version number if (timestamp[IRMA_VERIFIER_METADATA_OFFSET] != 0x01) { printf("Invalid metadata attribute found!\n"); } else { // Reconstruct expiry data from metadata expires = 0; expires += timestamp[IRMA_VERIFIER_METADATA_OFFSET + 1] << 16; expires += timestamp[IRMA_VERIFIER_METADATA_OFFSET + 2] << 8; expires += timestamp[IRMA_VERIFIER_METADATA_OFFSET + 3]; expires *= 86400; // convert days to seconds } } else { // This is old style expires = (timestamp[timestamp.size() - 2] << 8) + (timestamp[timestamp.size() - 1]); expires *= 86400; // convert days to seconds } printf("%s: %s\n", msg.c_str(), ctime(&expires)); }
bool silvia_pcsc_card::transmit(bytestring APDU, bytestring& data, unsigned short& sw) { if (!transmit(APDU, data)) { return false; } sw = data[data.size() - 2] << 8; sw += data[data.size() - 1]; data.resize(data.size() - 2); return true; }
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; } } } }
std::string hex(const bytestring &input) { std::string output; output.reserve(input.size() * 2); (void) boost::algorithm::hex(input, std::back_inserter(output)); return output; }
boost::multiprecision::cpp_int le32_to_cpp_int(const bytestring &le32) { boost::multiprecision::cpp_int mpi(0); for ( int i = le32.size(); i >= 0; i-- ) { mpi = (mpi << 8) + le32[i]; } return mpi; }
/** * Add a topic name and request its corresponding topic keys from the security server * @param string topic_name * @param string port_number port number of the node */ void Client::addTopic(bytestring topic_name, std::string port_number) { this->topics.push_back(topic_name); this->topic_ports[topic_name] = port_number; // create topic join request Message request(this->id, topic_name, "topic_join"); // sign with private key request.sign(this->key_pair.getPrivate()); this->log("sent topic join request for " + topic_name.str()); Message response = send(request, port_number); // verify response with security server public key if (!response.verify(this->sec_server_key)) { this->log("could not verify:", response); return; } // decrypt with private key if (!response.decrypt(this->key_pair.getPrivate())) { this->log("could not decrypt:", response); return; } if (response.getData().size() == 0) { this->log("received an empty topic join response for " + topic_name.str()); return; } this->log("received topic keys for " + topic_name.str()); // store the topic keypair TopicKeyPair topic_key_pair(response.getData()); this->topic_keys[topic_name] = topic_key_pair; }
bool edna_emulator::transceive_control(SCARDHANDLE reader, const bytestring& cmd, bytestring& rdata) { DWORD pcsc_rv; DWORD rlen; rdata.resize(512); if ((pcsc_rv = SCardControl(reader, IOCTL_CCID_ESCAPE_DIRECT, cmd.const_byte_str(), cmd.size(), rdata.byte_str(), 512, &rlen)) != SCARD_S_SUCCESS) { ERROR_MSG("Failed to exchange control command (0x%08X)", pcsc_rv); SCardDisconnect(reader, SCARD_UNPOWER_CARD); SCardReleaseContext(pcsc_context); return false; } rdata.resize(rlen); return true; }
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"; } }
bool silvia_pcsc_card::transmit(bytestring APDU, bytestring& data_sw) { if (!connected) return false; data_sw.resize(65536); DWORD out_len = 65536; SCARD_IO_REQUEST recv_req; LONG rv = SCardTransmit( card_handle, protocol == SCARD_PROTOCOL_T0 ? SCARD_PCI_T0 : SCARD_PCI_T1, APDU.byte_str(), APDU.size(), &recv_req, data_sw.byte_str(), &out_len); if (rv != SCARD_S_SUCCESS) { return false; } data_sw.resize(out_len); if (data_sw.size() < 2) { return false; } return true; }
/** * Add a topic name and request its corresponding topic keys from the security server * @param string topic_name * @param string port_number port number of the node */ void CardClient::addTopic(bytestring topic_name, std::string port_number) { this->topics.push_back(topic_name); this->topic_ports[topic_name] = port_number; // create topic join request Message request(this->id, topic_name, "topic_join"); request.sign(this->card); this->log("sent topic join request for (signed on card) " + topic_name.str()); Message response = send(request, port_number); if (!response.handleTopicKeyResponse(card)) { this->log("could not store topic keys for " + topic_name.str()); return; } this->log("received topic keys for " + topic_name.str()); }
bool silvia_nfc_card::transmit(bytestring APDU, bytestring& data_sw) { if (!connected) return false; data_sw.resize(65536); int out_len = nfc_initiator_transceive_bytes(device, APDU.byte_str(), APDU.size(), data_sw.byte_str(), data_sw.size(), 0); if (out_len < 2) { return false; } data_sw.resize(out_len); if (data_sw.size() < 2) { return false; } return true; }
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; } } } } } }
void pivacy_cardemu_emulator::process_apdu(bytestring& c_apdu, bytestring& r_apdu) { if (!ui_connected) { if ((pivacy_ui_connect() != PRV_OK) && !ui_optional) { ERROR_MSG("Not connected to the UI"); r_apdu = SW_UNKNOWN_ERROR; return; } INFO_MSG("Connected to the Pivacy UI"); ui_connected = true; } if (c_apdu.size() < 4) { ERROR_MSG("Malformed command APDU of %d bytes", c_apdu.size()); r_apdu = SW_UNKNOWN_ERROR; return; } switch(c_apdu[OFS_CLA]) { case CLA_ISO: switch(c_apdu[OFS_INS]) { case INS_SELECT: process_select(c_apdu, r_apdu); break; case INS_VERIFY_PIN: process_verify_pin(c_apdu, r_apdu); break; default: r_apdu = SW_UNKNOWN_INS; break; } break; case CLA_PRIVATE: switch(c_apdu[OFS_INS]) { case INS_PROVE_CREDENTIAL: process_prove_credential(c_apdu, r_apdu); break; case INS_PROVE_COMMITMENT: process_prove_commitment(c_apdu, r_apdu); break; case INS_PROVE_SIGNATURE: process_prove_signature(c_apdu, r_apdu); break; case INS_GET_RESPONSE: process_get_response(c_apdu, r_apdu); break; default: r_apdu = SW_UNKNOWN_INS; break; } break; default: r_apdu = SW_UNKNOWN_CLA; } }