package org.irmacard.personalisation;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.Properties;
import java.util.Random;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.TerminalFactory;
import net.sourceforge.scuba.smartcards.TerminalCardService;
import org.irmacard.credentials.Attributes;
import org.irmacard.credentials.idemix.IdemixCredentials;
import org.irmacard.credentials.idemix.IdemixPrivateKey;
import org.irmacard.credentials.idemix.spec.IdemixIssueSpecification;
import org.irmacard.credentials.idemix.test.TestSetup;
import org.irmacard.credentials.idemix.util.CredentialInformation;
import org.irmacard.credentials.idemix.util.IssueCredentialInformation;
import org.irmacard.credentials.info.DescriptionStore;
import org.irmacard.idemix.IdemixService;
public class CredentialLoader {
public static void main(String[] args) {
try {
Logger.log("main() called");
URI coreURI= new File(System.getProperty("user.dir")).toURI()
.resolve("irma_configuration/");
CredentialInformation.setCoreLocation(coreURI);
DescriptionStore.setCoreLocation(coreURI);
Properties config = readProperties(coreURI);
Connection con = getDatabaseConnection(config);
Card card = getCard(con, args[0]);
byte[] credentialPin = getRandomPin(4);
byte[] cardPin = getRandomPin(6);
Attributes attributes = new Attributes();
attributes.add("userID", card.getUserID().getBytes());
attributes.add("securityHash", hash(card.getUserID(), card.getCardId()));
IssueCredentialInformation ici = new IssueCredentialInformation("Surfnet", "root");
IdemixIssueSpecification spec = ici.getIdemixIssueSpecification();
IdemixPrivateKey isk = ici.getIdemixPrivateKey();
CardTerminal terminal = TerminalFactory.getDefault().terminals().list().get(0);
IdemixService is = new IdemixService(new TerminalCardService(terminal));
IdemixCredentials ic = new IdemixCredentials(is);
ic.connect();
is.sendCardPin(TestSetup.DEFAULT_CARD_PIN);
is.updateCardPin(TestSetup.DEFAULT_CARD_PIN, cardPin);
is.updateCredentialPin(credentialPin);
is.sendCredentialPin(credentialPin);
ic.issue(spec, isk, attributes, null);
sendMail(cardPin, credentialPin, card, config);
setCardStatusPersonalized(con, card.getCardId());
System.exit(0);
}
catch(Exception e) {
System.err.println("Exception in Credential Loader: " + e.toString());
Logger.log("Exception in Credential Loader: " + e.toString());
Logger.log("Exception:", e);
e.printStackTrace();
System.exit(1);
}
}
private static Connection getDatabaseConnection(Properties config) throws SQLException {
Connection con = DriverManager.getConnection(config.getProperty("database_url"), config.getProperty("database_username"), config.getProperty("database_password"));
return con;
}
private static byte[] getRandomPin(int length) {
Random rand = new Random();
byte[] pin = new byte[length];
for(int i = 0; i < length; i++) {
pin[i] = (byte) (rand.nextInt(10) + 0x30);
}
return pin;
}
private static void sendMail(byte[] cardPin, byte[] credentialPin, Card card, final Properties config) throws MessagingException {
String cardPinString = new String(cardPin);
String credentialPinString = new String(credentialPin);
Properties props = System.getProperties();
props.put("mail.smtp.host", config.getProperty("smtpServer"));
Session session = Session.getDefaultInstance(props);
Message msg = new MimeMessage(session);/*{
@Override
protected void updateMessageID() throws MessagingException {
super.updateMessageID();
String messageId = getMessageID();
String fromAdres = config.getProperty("fromAdres");
setHeader("Message-ID", messageId.substring(0, messageId.indexOf('@')) + fromAdres.substring(fromAdres.indexOf('@')));
}
};*/
try {
msg.setFrom(new InternetAddress(config.getProperty("fromAdres")));
} catch (AddressException e) {
e.printStackTrace();
}
msg.setRecipient(Message.RecipientType.TO, new InternetAddress(card.getEmail()));
msg.setSubject(config.getProperty("mailSubject"));
msg.setText(config.getProperty("mailBody").replace("$NAME$", card.getName()).replace("$CARD_PIN$", cardPinString).replace("$CREDENTIAL_PIN$", credentialPinString));
msg.setSentDate(new Date());
Transport.send(msg);
}
private static Properties readProperties(URI coreURI) throws IOException {
URI config = coreURI.resolve("config.properties.txt");
BufferedReader bufferedReader = new BufferedReader(new FileReader(new File(config)));
StringBuilder sb = new StringBuilder();
String line;
while((line = bufferedReader.readLine()) != null) {
sb.append(line);
sb.append(String.format("%n"));
}
bufferedReader.close();
Properties props = new Properties();
props.load(new StringReader(sb.toString()));
return props;
}
private static byte[] hash(String... strings) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
for(String string : strings) {
digest.update(string.getBytes());
}
return digest.digest();
}
private static Card getCard(Connection con, String cardId) throws SQLException {
PreparedStatement stmt = null;
String sql = "SELECT eduPersonPrincipalName, givenName, surname, email " +
"FROM PilotParticipants "+
"WHERE cardid = ?";
try {
stmt = con.prepareStatement(sql);
stmt.setString(1, cardId);
ResultSet result = stmt.executeQuery();
if(result.next()) {
String userID = result.getString("eduPersonPrincipalName");
String name = result.getString("givenName") + " " + result.getString("surname");
String email = result.getString("email");
return new Card(userID, name, email, null, cardId);
} else {
return null;
}
} finally {
if (stmt != null) {
stmt.close();
}
}
}
private static void setCardStatusPersonalized(Connection con, String cardId) throws SQLException {
PreparedStatement stmt = null;
String sql = "UPDATE PilotParticipants SET cardStatus = 'personalised' WHERE cardId = ?";
try {
stmt = con.prepareStatement(sql);
stmt.setString(1, cardId);
int numUpdated = stmt.executeUpdate();
Logger.log("Updated " + numUpdated + " rows");
} catch (Exception e) {
Logger.log("Update failed: " + e.getMessage(), e);
} finally {
if (stmt != null) {
stmt.close();
}
}
}
}