//* Licensed Materials - Property of * //* IBM * //* Alexandra Instituttet A/S * //* * //* eu.abc4trust.pabce.1.34 * //* * //* (C) Copyright IBM Corp. 2014. All Rights Reserved. * //* (C) Copyright Alexandra Instituttet A/S, Denmark. 2014. All * //* Rights Reserved. * //* US Government Users Restricted Rights - Use, duplication or * //* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. * //* * //* This file is licensed under the Apache License, Version 2.0 (the * //* "License"); you may not use this file except in compliance with * //* the License. You may obtain a copy of the License at: * //* http://www.apache.org/licenses/LICENSE-2.0 * //* Unless required by applicable law or agreed to in writing, * //* software distributed under the License is distributed on an * //* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * //* KIND, either express or implied. See the License for the * //* specific language governing permissions and limitations * //* under the License. * //*/**/**************************************************************** package eu.abc4trust.smartcard; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; import org.junit.Test; import eu.abc4trust.abce.testharness.ImagePathBuilder; import eu.abc4trust.cryptoEngine.user.CredentialSerializer; import eu.abc4trust.cryptoEngine.user.CredentialSerializerGzipXml; import eu.abc4trust.cryptoEngine.user.PseudonymSerializer; import eu.abc4trust.cryptoEngine.user.PseudonymSerializerGzipXml; import eu.abc4trust.xml.Credential; import eu.abc4trust.xml.CredentialDescription; import eu.abc4trust.xml.CryptoParams; import eu.abc4trust.xml.Pseudonym; import eu.abc4trust.xml.PseudonymWithMetadata; public class SoftwareSmartcardTest { private static final int pin = 1234; private static int puk = 12345678; private static BigInteger challenge; private static final URI deviceURI = URI.create("ImbaDeviceNo42"); private static final Random rand = new Random(42); private static final CredentialSerializer serializer = new CredentialSerializerGzipXml(); public static SoftwareSmartcard setupSmartcard() { //init the structure store //StructureStore.getInstance().add(IdemixConstants.groupParameterId, StaticGroupParameters.getGroupParameters()); short deviceID = 1; SystemParameters sp = getSystemParameters(); // deviceSecret = 86127401088496880082801127003646828744375250417716244414750855766766755168176 SoftwareSmartcard s = new SoftwareSmartcard(new Random(42)); RSAKeyPair key = RSASignatureSystemTest.getSigningKeyForTest(); puk = s.init(pin, sp, key, deviceID); SmartcardBlob deviceUriBlob = new SmartcardBlob(); try { deviceUriBlob.blob = deviceURI.toASCIIString().getBytes("US-ASCII"); } catch (UnsupportedEncodingException e) { throw new RuntimeException("US-ASCII not supported exception.", e); } s.storeBlob(pin, Smartcard.device_name, deviceUriBlob); //Setup challenge to new random challenge = new BigInteger(32, rand); return s; } public static SmartcardParameters getCredentialBases() { BigInteger p = new BigInteger("13983014021825029330432041492790970071621084464773656969911606241061807342940154950776220801109453405514836004504505950014655952003125355018122289242812307"); BigInteger q = new BigInteger("4263165099819514102133474591208918364260622516330751115416512365230148267352138796296838231373257204547230954382685845694047366165171100272638554618056287"); // n = 59611897368131366507364942276670668747995323268474975289271614234218937009935107719366762946802866847720072176517579036188074246487493444834020695796207762776438347095237876273178780516676456685032464805596922499374627605877256498945463430940126396361032161179291118883563104866211893115282075236693902324109 BigInteger n = p.multiply(q); BigInteger R0 = BigInteger.valueOf(4); BigInteger S = BigInteger.valueOf(9); return SmartcardParameters.forTwoBaseCl(n, R0, S); } private static SystemParameters getSystemParameters() { SystemParameters sp = new SystemParameters(); // A 257.9-bit safe prime sp.p = new BigInteger("434669094696085191199122398486087525063835578234110975424949095034621531078563"); sp.g = BigInteger.valueOf(3); sp.subgroupOrder = sp.p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); sp.deviceSecretSizeBytes = 256 / 8; sp.signatureNonceLengthBytes = 80 / 8; sp.zkChallengeSizeBytes = 256; sp.zkStatisticalHidingSizeBytes = 80 / 8; return sp; } @Test public void testNonInitialized() { SoftwareSmartcard s = new SoftwareSmartcard(rand); URI someUri = URI.create("Hello"); int pin = 1234; String password =""; RSAKeyPair rs = new RSAKeyPair(BigInteger.ZERO, BigInteger.ZERO); RSAVerificationKey rv = new RSAVerificationKey(); rv.n = BigInteger.ZERO; SmartcardParameters cb = SmartcardParameters.forTwoBaseCl(BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO); assertEquals(s.addIssuerParameters(rs, someUri, cb), SmartcardStatusCode.NOT_INITIALIZED); assertEquals(s.addIssuerParametersWithAttendanceCheck(rs, someUri, 0, cb, rv, 0), SmartcardStatusCode.NOT_INITIALIZED); assertEquals(s.allocateCredential(0, someUri, someUri), SmartcardStatusCode.NOT_INITIALIZED); assertEquals(s.backupAttendanceData(0, password), null); assertEquals(s.changePin(0, 0), SmartcardStatusCode.NOT_INITIALIZED); assertEquals(s.computeCredentialFragment(0, null), null); assertEquals(s.computeDevicePublicKey(0), null); assertEquals(s.computeScopeExclusivePseudonym(0, null), null); assertEquals(s.deleteBlob(0, null), SmartcardStatusCode.NOT_INITIALIZED); assertEquals(s.deleteCredential(0, null), SmartcardStatusCode.NOT_INITIALIZED); assertEquals(s.deleteIssuer(pin, someUri, null), SmartcardStatusCode.NOT_INITIALIZED); assertEquals(s.finalizeZkProof(0, null, null, null), null); assertEquals(s.getBlob(0, null), null); assertEquals(s.getBlobs(0), null); assertEquals(s.getBlobUris(0), null); assertEquals(s.getCourse(0, null), null); assertEquals(s.getDeviceURI(0), null); assertEquals(s.getIssuerParameters(0, null), null); assertEquals(s.getIssuerParametersList(0), null); assertEquals(s.getIssuerParametersOfCredential(0, null), null); assertEquals(s.getNewNonceForSignature(), null); assertEquals(s.getSystemParameters(0), null); assertEquals(s.incrementCourseCounter(0, null, null, 0), SmartcardStatusCode.NOT_INITIALIZED); assertEquals(s.listCourses(0), null); assertEquals(s.listCredentialsUris(0), null); assertEquals(s.pinTrialsLeft(), 0); assertEquals(s.prepareZkProof(0, null, null, false), null); assertEquals(s.pukTrialsLeft(), 0); assertEquals(s.resetPinWithPuk(0, 0), SmartcardStatusCode.NOT_INITIALIZED); assertEquals(s.smartcardPresent(), true); assertEquals(s.storeBlob(0, URI.create(""), null), SmartcardStatusCode.NOT_INITIALIZED); assertEquals(s.wasInit(), false); } @Test public void testBackup(){ RSAKeyPair key = RSASignatureSystemTest.getSigningKeyForTest(); SoftwareSmartcard s = setupSmartcard(); String password = "87654321"; //no credentials SmartcardBackup backup = s.backupAttendanceData(pin, password); assertNotNull(backup); s = setupSmartcard(); assertEquals(s.restoreAttendanceData(pin, password, backup), SmartcardStatusCode.OK); //now with issuer and credentials s = setupSmartcard(); URI issuerURI = URI.create("issuer1"); URI credentialUri = URI.create("cred1"); SmartcardParameters credBases = getCredentialBases(); s.getNewNonceForSignature(); assertEquals(s.addIssuerParametersWithAttendanceCheck(key, issuerURI, 1, credBases, RSASignatureSystem.getVerificationKey(key), 2), SmartcardStatusCode.OK); assertEquals(s.allocateCredential(pin, credentialUri, issuerURI), SmartcardStatusCode.OK); assertEquals(s.listCredentialsUris(pin).size(), 1); assertEquals(s.listCourses(pin).size(), 1); SmartcardBlob blob = new SmartcardBlob(); blob.blob = issuerURI.toASCIIString().getBytes(); assertEquals(s.storeBlob(pin, issuerURI, blob), SmartcardStatusCode.OK); Set<URI> credentialIds = new HashSet<URI>(); credentialIds.add(credentialUri); s.prepareZkProof(pin, credentialIds, new HashSet<URI>(), false); //just to activate the course. for(int i = 1; i <= 2; i++){ s.getNewNonceForSignature(); assertEquals(s.incrementCourseCounter(pin, key, issuerURI, i), SmartcardStatusCode.OK); } assertEquals(2, s.getCounterValue(pin, issuerURI)); backup = s.backupAttendanceData(pin, password); assertNotNull(backup); s = setupSmartcard(); s.getNewNonceForSignature(); assertEquals(s.addIssuerParametersWithAttendanceCheck(key, issuerURI, 1, credBases, RSASignatureSystem.getVerificationKey(key), 2), SmartcardStatusCode.OK); assertEquals(s.allocateCredential(pin, credentialUri, issuerURI), SmartcardStatusCode.OK); assertEquals(s.listCredentialsUris(pin).size(), 1); assertEquals(s.listCourses(pin).size(), 1); blob = new SmartcardBlob(); blob.blob = issuerURI.toASCIIString().getBytes(); assertEquals(s.storeBlob(pin, issuerURI, blob), SmartcardStatusCode.OK); assertEquals(0, s.getCounterValue(pin, issuerURI)); assertEquals(s.restoreAttendanceData(pin, password, backup), SmartcardStatusCode.OK); assertEquals(2, s.getCounterValue(pin, issuerURI)); assertEquals(s.listCredentialsUris(pin).size(), 1); assertEquals(s.listCourses(pin).size(), 1); assertEquals(s.getBlobUris(pin).size(), 2); //2 since the deviceUri is also in the blob store File f = new File("softwareSCBackup.bac"); backup.serialize(f); } @Test public void testRestore(){ SoftwareSmartcard s = setupSmartcard(); URI issuerURI = URI.create("issuer1"); URI credentialUri = URI.create("cred1"); SmartcardParameters credBases = getCredentialBases(); RSAKeyPair key = RSASignatureSystemTest.getSigningKeyForTest(); s.getNewNonceForSignature(); assertEquals(s.addIssuerParametersWithAttendanceCheck(key, issuerURI, 1, credBases, RSASignatureSystem.getVerificationKey(key), 2), SmartcardStatusCode.OK); assertEquals(s.allocateCredential(pin, credentialUri, issuerURI), SmartcardStatusCode.OK); assertEquals(s.listCredentialsUris(pin).size(), 1); assertEquals(s.listCourses(pin).size(), 1); SmartcardBlob blob = new SmartcardBlob(); blob.blob = issuerURI.toASCIIString().getBytes(); assertEquals(s.storeBlob(pin, issuerURI, blob), SmartcardStatusCode.OK); File f = new File("softwareSCBackup.bac"); SmartcardBackup backup = SmartcardBackup.deserialize(f); String password = "87654321"; assertEquals(s.restoreAttendanceData(pin, password, backup), SmartcardStatusCode.OK); assertEquals(s.listCredentialsUris(pin).size(), 1); assertEquals(s.listCourses(pin).size(), 1); assertEquals(s.getBlobUris(pin).size(), 2); //2 since deviceUri is also in the blobstore assertEquals(deviceURI, s.getDeviceURI(pin)); assertEquals(2, s.getCounterValue(pin, issuerURI)); assertTrue(Arrays.equals(s.getBlob(pin, issuerURI).blob, issuerURI.toASCIIString().getBytes())); f.delete(); } @Test public void testStoreCredential(){ SoftwareSmartcard s = setupSmartcard(); Random r = new Random(1234); URI longURI1 = URI.create(new BigInteger(2048*3, r).toString()); URI longURI2 = URI.create(new BigInteger(2048*2, r).toString()); URI longURI3 = URI.create(new BigInteger(2048*2, r).toString()); System.out.println("credUID: " + longURI3); byte[] loongByteArr = new byte[2048*2+256]; Credential cred = new Credential(); CryptoParams cryptoParam = new CryptoParams(); CredentialDescription credDesc = new CredentialDescription(); credDesc.setImageReference(ImagePathBuilder.TEST_IMAGE_JPG); credDesc.setIssuerParametersUID(longURI2); credDesc.setCredentialSpecificationUID(longURI2); credDesc.setCredentialUID(longURI3); cred.setCredentialDescription(credDesc); cred.setCryptoParams(cryptoParam); URI credentialId = URI.create("credUri"); s.storeCredential(pin, credentialId, cred, serializer); Credential credPrime = s.getCredential(pin, credentialId, serializer); CredentialDescription credDescriptionPrime = credPrime.getCredentialDescription(); System.out.println("from read credential - credUID: "+credDescriptionPrime.getCredentialUID().toString()); assertEquals(credDesc.getCredentialUID(), credDescriptionPrime.getCredentialUID()); byte[] origCredSerialized = serializer.serializeCredential(cred); byte[] newCredSerialized = serializer.serializeCredential(credPrime); System.out.println("orig: " + origCredSerialized.length+", new: " + newCredSerialized.length); assertTrue(Arrays.equals(origCredSerialized, newCredSerialized)); //Now test pseudonym storage PseudonymWithMetadata pseudonym = new PseudonymWithMetadata(); Pseudonym pseu = new Pseudonym(); pseu.setExclusive(true); URI pseudonymUID = URI.create("pseudonymUri"); pseu.setPseudonymUID(pseudonymUID); pseu.setPseudonymValue(loongByteArr); pseu.setScope("testScope"); pseu.setSecretReference(deviceURI); pseudonym.setPseudonym(pseu); pseudonym.setCryptoParams(cryptoParam); CardStorage cardStorage = new CardStorage(); cardStorage.addSmartcard(s, pin); PseudonymSerializer pseudonymSerializer = new PseudonymSerializerGzipXml(cardStorage); System.out.println("After this line"); s.storePseudonym(pin, pseudonymUID, pseudonym, pseudonymSerializer); PseudonymWithMetadata pseudonymPrime = s.getPseudonym(pin, pseu.getPseudonymUID(), pseudonymSerializer); byte[] first = pseudonymSerializer.serializePseudonym(pseudonym); byte[] second = pseudonymSerializer.serializePseudonym(pseudonymPrime); assertTrue(Arrays.equals(first, second)); } @Test public void testPin() { SoftwareSmartcard s = new SoftwareSmartcard(); SystemParameters sp = new SystemParameters(); sp.deviceSecretSizeBytes = 128 / 8; short deviceID = 1; RSAKeyPair key = RSASignatureSystemTest.getSigningKeyForTest(); SoftwareSmartcardTest.puk = s.init(pin, sp, key, deviceID); assertEquals(3, s.pinTrialsLeft()); assertEquals(SmartcardStatusCode.OK, s.changePin(pin, pin)); assertEquals(3, s.pinTrialsLeft()); assertEquals(SmartcardStatusCode.UNAUTHORIZED, s.changePin(pin-1, pin)); assertEquals(SmartcardStatusCode.UNAUTHORIZED, s.changePin(pin-1, pin)); assertEquals(1, s.pinTrialsLeft()); assertEquals(SmartcardStatusCode.OK, s.changePin(pin, pin)); assertEquals(3, s.pinTrialsLeft()); assertEquals(SmartcardStatusCode.UNAUTHORIZED, s.changePin(pin-1, pin)); assertEquals(SmartcardStatusCode.UNAUTHORIZED, s.changePin(pin-1, pin)); assertEquals(SmartcardStatusCode.FORBIDDEN, s.changePin(pin-1, pin)); assertEquals(SmartcardStatusCode.FORBIDDEN, s.changePin(pin, pin)); assertEquals(0, s.pinTrialsLeft()); assertEquals(SmartcardStatusCode.OK, s.resetPinWithPuk(puk, pin)); assertEquals(3, s.pinTrialsLeft()); assertEquals(10, s.pukTrialsLeft()); for(int i=9; i>=1; --i) { assertEquals(SmartcardStatusCode.UNAUTHORIZED, s.resetPinWithPuk(puk-1, pin)); assertEquals(i, s.pukTrialsLeft()); } assertEquals(SmartcardStatusCode.OK, s.resetPinWithPuk(puk, pin)); assertEquals(10, s.pukTrialsLeft()); for(int i=9;i>=1;--i) { assertEquals(SmartcardStatusCode.UNAUTHORIZED, s.resetPinWithPuk(puk-1, pin)); assertEquals(i, s.pukTrialsLeft()); } assertEquals(SmartcardStatusCode.FORBIDDEN, s.resetPinWithPuk(puk-1, pin)); assertEquals(0, s.pukTrialsLeft()); assertEquals(SmartcardStatusCode.FORBIDDEN, s.resetPinWithPuk(puk, pin)); assertEquals(0, s.pukTrialsLeft()); } @Test public void testEmptyProof() { SoftwareSmartcard s = setupSmartcard(); ZkProofCommitment com = s.prepareZkProof(pin, new HashSet<URI>(), new HashSet<URI>(), false); ZkProofResponse res = s.finalizeZkProof(pin, challenge, new HashSet<URI>(), new HashSet<URI>()); assertTrue(ZkProofSystem.checkProof(com, res, challenge)); // There are no witnesses, so the challenge doesn't actually matter assertTrue(ZkProofSystem.checkProof(com, res, BigInteger.ZERO)); } @Test public void testNormalPseudonym() { SoftwareSmartcard s = setupSmartcard(); // Normal pseudonym BigInteger publicKey = s.computeDevicePublicKey(pin); BigInteger deviceSecret = new BigInteger("81947287742789796125923186813596954448492990520405884824178747062075036638517"); SystemParameters params = getSystemParameters(); BigInteger devicePk = params.g.modPow(deviceSecret, params.p); // TODO (ms) Check with Kasper if this is ok // assertEquals(devicePk, publicKey); ZkProofCommitment com = s.prepareZkProof(pin, new HashSet<URI>(), new HashSet<URI>(), true); // ZkNonceCommitmentOpening nco = s.zkNonceOpen(pin, nonceCom); // List<ZkNonceCommitmentOpening> ncol = new ArrayList<ZkNonceCommitmentOpening>(); // ncol.add(nco); //byte[] nonceCommitment = Utils.hashConcat(nonceCom); ZkProofResponse res = s.finalizeZkProof(pin, challenge, new HashSet<URI>(), new HashSet<URI>()); assertTrue(ZkProofSystem.checkProof(com, res, challenge)); assertFalse(ZkProofSystem.checkProof(com, res, BigInteger.ZERO)); } @Test public void testScopeExclusivePseudonym() { SoftwareSmartcard s = setupSmartcard(); // Scope exclusive pseudonym BigInteger base = new BigInteger("427356031130966532512025830811427122551813236122182141128982542568625228427612"); BigInteger deviceSecret = new BigInteger("81947287742789796125923186813596954448492990520405884824178747062075036638517"); // scope-exclusive pseudonym = base^deviceSecret URI scope = URI.create("Hello"); // TODO (ms) Check with Kasper if this is ok // assertEquals(s.computeScopeExclusivePseudonym(pin, scope),base.modPow(deviceSecret, getSystemParameters().p)); Set<URI> scopeList = new HashSet<URI>(); scopeList.add(scope); ZkProofCommitment com = s.prepareZkProof(pin, new HashSet<URI>(), scopeList, false); // List<byte[]> nonceCom = new ArrayList<byte[]>(); // nonceCom.add(com.nonceCommitment); // ZkNonceCommitmentOpening nco = s.zkNonceOpen(pin, nonceCom); // List<ZkNonceCommitmentOpening> ncol = new ArrayList<ZkNonceCommitmentOpening>(); // ncol.add(nco); ZkProofResponse res = s.finalizeZkProof(pin, challenge, new HashSet<URI>(), new HashSet<URI>()); assertTrue(ZkProofSystem.checkProof(com, res, challenge)); assertFalse(ZkProofSystem.checkProof(com, res, BigInteger.ZERO)); } @Test public void testSimpleCredential() { SoftwareSmartcard s = setupSmartcard(); RSAKeyPair key = RSASignatureSystemTest.getSigningKeyForTest(); URI issuerUri = URI.create("issuer"); URI credUri = URI.create("credential"); SmartcardParameters cb = getCredentialBases(); s.getNewNonceForSignature(); assertEquals(s.addIssuerParameters(key, issuerUri, cb), SmartcardStatusCode.OK); assertEquals(s.allocateCredential(pin, credUri, issuerUri), SmartcardStatusCode.OK); Set<URI> credList = new HashSet<URI>(); credList.add(credUri); // First proof { ZkProofCommitment com = s.prepareZkProof(pin, credList, new HashSet<URI>(), false); assertNotNull(com); // List<byte[]> nonceCom = new ArrayList<byte[]>(); // nonceCom.add(com.nonceCommitment); // ZkNonceCommitmentOpening nco = s.zkNonceOpen(pin, nonceCom); // List<ZkNonceCommitmentOpening> ncol = new ArrayList<ZkNonceCommitmentOpening>(); // ncol.add(nco); ZkProofResponse res = s.finalizeZkProof(pin, challenge, credList, new HashSet<URI>()); assertTrue(ZkProofSystem.checkProof(com, res, challenge)); assertFalse(ZkProofSystem.checkProof(com, res, BigInteger.ZERO)); } // Second proof should work, since no attendance checks are done { ZkProofCommitment com = s.prepareZkProof(pin, credList, new HashSet<URI>(), false); assertNotNull(com); // List<byte[]> nonceCom = new ArrayList<byte[]>(); // nonceCom.add(com.nonceCommitment); // ZkNonceCommitmentOpening nco = s.zkNonceOpen(pin, nonceCom); // List<ZkNonceCommitmentOpening> ncol = new ArrayList<ZkNonceCommitmentOpening>(); // ncol.add(nco); ZkProofResponse res = s.finalizeZkProof(pin, challenge, credList, new HashSet<URI>()); assertTrue(ZkProofSystem.checkProof(com, res, challenge)); assertFalse(ZkProofSystem.checkProof(com, res,BigInteger.ZERO)); } } @Test public void testCourseCredential() { SoftwareSmartcard s = setupSmartcard(); RSAKeyPair rootKey = RSASignatureSystemTest.getSigningKeyForTest(); RSAKeyPair key2 = RSASignatureSystemTest.getAnotherSigningKeyForTest(); RSAVerificationKey cvk = RSASignatureSystem.getVerificationKey(key2); int minAttendance = 2; URI issuerUri = URI.create("issuer"); URI credUri = URI.create("credential"); SmartcardParameters cb = getCredentialBases(); { s.getNewNonceForSignature(); assertEquals(s.addIssuerParametersWithAttendanceCheck(rootKey, issuerUri, 1, cb, cvk, minAttendance), SmartcardStatusCode.OK); } assertEquals(s.allocateCredential(pin, credUri, issuerUri), SmartcardStatusCode.OK); // Course counter should be disabled before issuance { int lectureId = 42; s.getNewNonceForSignature(); assertEquals(s.incrementCourseCounter(pin, key2, issuerUri, lectureId), SmartcardStatusCode.NOT_MODIFIED); } Set<URI> credList = new HashSet<URI>(); credList.add(credUri); // Initial ZK proof = issuance { ZkProofCommitment com = s.prepareZkProof(pin, credList, new HashSet<URI>(), false); assertNotNull(com); // List<byte[]> nonceCom = new ArrayList<byte[]>(); // nonceCom.add(com.nonceCommitment); // ZkNonceCommitmentOpening nco = s.zkNonceOpen(pin, nonceCom); // List<ZkNonceCommitmentOpening> ncol = new ArrayList<ZkNonceCommitmentOpening>(); // ncol.add(nco); ZkProofResponse res = s.finalizeZkProof(pin, challenge, credList, new HashSet<URI>()); assertTrue(ZkProofSystem.checkProof(com, res, challenge)); assertFalse(ZkProofSystem.checkProof(com, res, BigInteger.ZERO)); } // Once the credential is issued, no more proofs until attendance check assertNull(s.prepareZkProof(pin, credList, new HashSet<URI>(), false)); // Increment course counter { int lectureId = 42; s.getNewNonceForSignature(); assertEquals(s.incrementCourseCounter(pin, key2, issuerUri, lectureId), SmartcardStatusCode.OK); } // Not enough attendance assertNull(s.prepareZkProof(pin, credList, new HashSet<URI>(), false)); // Replay attack protection { int lectureId = 42; s.getNewNonceForSignature(); assertEquals(s.incrementCourseCounter(pin, key2, issuerUri, lectureId), SmartcardStatusCode.NOT_MODIFIED); } // Not enough attendance assertNull(s.prepareZkProof(pin, credList, new HashSet<URI>(), false)); // Replay attack protection { int lectureId = 39; s.getNewNonceForSignature(); assertEquals(s.incrementCourseCounter(pin, key2, issuerUri, lectureId), SmartcardStatusCode.NOT_MODIFIED); } // Not enough attendance assertNull(s.prepareZkProof(pin, credList, new HashSet<URI>(), false)); // Increment counter { int lectureId = 43; s.getNewNonceForSignature(); assertEquals(s.incrementCourseCounter(pin, key2, issuerUri, lectureId), SmartcardStatusCode.OK); } // Now the proof works { ZkProofCommitment com = s.prepareZkProof(pin, credList, new HashSet<URI>(), false); assertNotNull(com); // List<byte[]> nonceCom = new ArrayList<byte[]>(); // nonceCom.add(com.nonceCommitment); // ZkNonceCommitmentOpening nco = s.zkNonceOpen(pin, nonceCom); // List<ZkNonceCommitmentOpening> ncol = new ArrayList<ZkNonceCommitmentOpening>(); // ncol.add(nco); ZkProofResponse res = s.finalizeZkProof(pin, challenge, credList, new HashSet<URI>()); assertTrue(ZkProofSystem.checkProof(com, res, challenge)); assertFalse(ZkProofSystem.checkProof(com, res, BigInteger.ZERO)); } } @Test public void testMultipleCredentialsAndPseudonyms() { SoftwareSmartcard s = setupSmartcard(); RSAKeyPair rootKey = RSASignatureSystemTest.getSigningKeyForTest(); URI issuerUriA = URI.create("issuerA"); URI issuerUriB = URI.create("issuerB"); URI credUriA1 = URI.create("credential1"); URI credUriA2 = URI.create("credential2"); URI credUriA3 = URI.create("credential3"); URI credUriB1 = URI.create("credential4"); URI credUriB2 = URI.create("credential5"); SmartcardParameters cb = getCredentialBases(); { s.getNewNonceForSignature(); assertEquals(s.addIssuerParameters(rootKey, issuerUriA, cb), SmartcardStatusCode.OK); } { RSAKeyPair key = RSASignatureSystemTest.getAnotherSigningKeyForTest(); RSAVerificationKey cvk = RSASignatureSystem.getVerificationKey(key); int minAttendance = 10; s.getNewNonceForSignature(); assertEquals(s.addIssuerParametersWithAttendanceCheck(rootKey, issuerUriB, 1, cb, cvk, minAttendance), SmartcardStatusCode.OK); } assertEquals(s.allocateCredential(pin, credUriA1, issuerUriA), SmartcardStatusCode.OK); assertEquals(s.allocateCredential(pin, credUriA2, issuerUriA), SmartcardStatusCode.OK); assertEquals(s.allocateCredential(pin, credUriA3, issuerUriA), SmartcardStatusCode.OK); assertEquals(s.allocateCredential(pin, credUriB1, issuerUriB), SmartcardStatusCode.OK); assertEquals(s.allocateCredential(pin, credUriB2, issuerUriB), SmartcardStatusCode.OK); Set<URI> credList = new HashSet<URI>(); credList.add(credUriA1); credList.add(credUriA2); credList.add(credUriA3); credList.add(credUriB1); // without B2 Set<URI> pseuList = new HashSet<URI>(); pseuList.add(URI.create("scope1")); pseuList.add(URI.create("scope2")); pseuList.add(URI.create("scope3")); // Initial ZK proof = issuance { ZkProofCommitment com = s.prepareZkProof(pin, credList, pseuList, true); assertNotNull(com); // List<byte[]> nonceCom = new ArrayList<byte[]>(); // nonceCom.add(com.nonceCommitment); // ZkNonceCommitmentOpening nco = s.zkNonceOpen(pin, nonceCom); // List<ZkNonceCommitmentOpening> ncol = new ArrayList<ZkNonceCommitmentOpening>(); // ncol.add(nco); ZkProofResponse res = s.finalizeZkProof(pin, challenge, credList, pseuList); assertTrue(ZkProofSystem.checkProof(com, res, challenge)); assertFalse(ZkProofSystem.checkProof(com, res, BigInteger.ZERO)); } credList.remove(credUriB1); credList.add(credUriB2); // B2 is issued here, (B1 not in the proof), other credentials don't have attendance check { ZkProofCommitment com = s.prepareZkProof(pin, credList, pseuList, true); assertNotNull(com); // List<byte[]> nonceCom = new ArrayList<byte[]>(); // nonceCom.add(com.nonceCommitment); // ZkNonceCommitmentOpening nco = s.zkNonceOpen(pin, nonceCom); // List<ZkNonceCommitmentOpening> ncol = new ArrayList<ZkNonceCommitmentOpening>(); // ncol.add(nco); ZkProofResponse res = s.finalizeZkProof(pin, challenge, credList, pseuList); assertTrue(ZkProofSystem.checkProof(com, res, challenge)); assertFalse(ZkProofSystem.checkProof(com, res, BigInteger.ZERO)); } // Now the attendance check kicks in assertNull(s.prepareZkProof(pin, credList, pseuList, true)); } }