/*
* A CCNx library test.
*
* Copyright (C) 2008, 2009, 2011, 2012 Palo Alto Research Center, Inc.
*
* This work is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the
* Free Software Foundation.
* This work is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details. You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
package org.ccnx.ccn.test.io.content;
import java.io.IOException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.ccnx.ccn.CCNHandle;
import org.ccnx.ccn.config.ConfigurationException;
import org.ccnx.ccn.config.SystemConfiguration;
import org.ccnx.ccn.impl.CCNFlowControl.SaveType;
import org.ccnx.ccn.impl.support.Log;
import org.ccnx.ccn.io.CCNOutputStream;
import org.ccnx.ccn.io.content.PublicKeyObject;
import org.ccnx.ccn.profiles.SegmentationProfile;
import org.ccnx.ccn.profiles.VersionMissingException;
import org.ccnx.ccn.profiles.VersioningProfile;
import org.ccnx.ccn.protocol.ContentName;
import org.ccnx.ccn.protocol.ContentObject;
import org.ccnx.ccn.test.CCNTestHelper;
import org.ccnx.ccn.test.Flosser;
import org.ccnx.ccn.test.TestUtils;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
/**
* Test reading and writing versioned, encoded PublicKeys to a repository. We have
* separated out reading and writing El Gamal and ECC public keys, because BouncyCastle
* doesn't support all algorithms out of the box on certain platforms. See
* apps/extras/ExpandedCryptoTests for the full tests.
*/
public class PublicKeyObjectTestRepo {
/**
* Handle naming for the test
*/
static CCNTestHelper testHelper = new CCNTestHelper(PublicKeyObjectTestRepo.class);
public static KeyPair pair1 = null;
public static KeyPair pair2 = null;
public static KeyPair dsaPair = null;
public static KeyPair dhPair = null;
public static int NUM_ALGORITHMS = 3;
public static ContentName [][] storedKeyNames = new ContentName[2][NUM_ALGORITHMS];
public static ContentName namespace = null;
static Flosser flosser = null;
public static CCNHandle handle = null;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
handle = CCNHandle.open();
Security.addProvider(new BouncyCastleProvider());
// generate key pair
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024); // go for fast
pair1 = kpg.generateKeyPair();
pair2 = kpg.generateKeyPair();
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
keyGen.initialize(1024);
dsaPair = keyGen.genKeyPair();
// Generate a 576-bit DH key pair
keyGen = KeyPairGenerator.getInstance("DH");
keyGen.initialize(576);
dhPair = keyGen.genKeyPair();
namespace = new ContentName(testHelper.getClassNamespace(), "Users");
for (int i=0; i < storedKeyNames.length; ++i) {
storedKeyNames[i][0] = new ContentName(namespace, "testRSAUser-" + i, "KEY");
storedKeyNames[i][1] = new ContentName(namespace, "testDSAUser-" + i, "KEY");
storedKeyNames[i][2] = new ContentName(namespace, "testDHUser-" + i, "KEY");
}
}
@AfterClass
public static void cleanupAfterClass() {
handle.close();
}
@Test
public void testRawPublicKeyObject() throws Exception {
Log.info(Log.FAC_TEST, "Starting testRawPublicKeyObject");
try {
testRawKeyReadWrite(storedKeyNames[0][0], pair1.getPublic(), pair2.getPublic());
testRawKeyReadWrite(storedKeyNames[0][1], dsaPair.getPublic(), null);
testRawKeyReadWrite(storedKeyNames[0][2], dhPair.getPublic(), null);
} finally {
Log.info(Log.FAC_TEST, "PublicKeyObjectTestRepo: Stopping flosser.");
flosser.stop();
flosser = null;
Log.info(Log.FAC_TEST, "PublicKeyObjectTestRepo: Flosser stopped.");
}
Log.info(Log.FAC_TEST, "Completed testRawPublicKeyObject");
}
@Test
public void testRepoPublicKeyObject() throws Exception {
Log.info(Log.FAC_TEST, "Starting testRepoPublicKeyObject");
testRepoKeyReadWrite(storedKeyNames[1][0], pair1.getPublic(), pair2.getPublic());
testRepoKeyReadWrite(storedKeyNames[1][1], dsaPair.getPublic(), null);
testRepoKeyReadWrite(storedKeyNames[1][2], dhPair.getPublic(), null);
Log.info(Log.FAC_TEST, "Completed testRepoPublicKeyObject");
}
@Test
public void testUnversionedPublicKeyObject() throws Exception {
// we might want to use a PKO to read an object written without a version.
ContentName unversionedName = new ContentName(testHelper.getTestNamespace("testUnversionedPublicKeyObject"), "unversionedKey");
if (null == flosser) {
flosser = new Flosser();
}
flosser.handleNamespace(unversionedName);
CCNOutputStream writeStream = new CCNOutputStream(unversionedName, handle);
writeStream.write(pair1.getPublic().getEncoded());
writeStream.close();
Log.info(Log.FAC_TEST, "Saved unversioned key to name {0}, now trying to read.", unversionedName);
CCNHandle otherHandle = CCNHandle.open();
ContentObject firstSegment = SegmentationProfile.getSegment(unversionedName, null, null,
SystemConfiguration.getDefaultTimeout(), null, otherHandle);
if (null == firstSegment) {
Log.warning(Log.FAC_TEST, "Cannot retrieve segment of stream {0}", unversionedName);
Assert.fail("Cannot retrieve first segment: " + unversionedName);
}
PublicKeyObject testObject = new PublicKeyObject(firstSegment, CCNHandle.open());
Log.info(Log.FAC_TEST, "testObject available? " + testObject.available());
otherHandle.close();
testObject.close();
Log.info(Log.FAC_TEST, "Completed testRepoPublicKeyObject");
}
public void testRawKeyReadWrite(ContentName keyName, PublicKey key, PublicKey optional2ndKey) throws ConfigurationException, IOException, VersionMissingException {
Log.info(Log.FAC_TEST, "Reading and writing raw key " + keyName + " key 1: " + key.getAlgorithm() + " key 2: " + ((null == optional2ndKey) ? "null" : optional2ndKey.getAlgorithm()));
if (null == flosser) {
flosser = new Flosser();
}
flosser.handleNamespace(keyName);
PublicKeyObject pko = new PublicKeyObject(keyName, key, SaveType.RAW, handle);
pko.save();
Log.info(Log.FAC_TEST, "Saved " + pko.getVersionedName() + ", now trying to read.");
Assert.assertTrue(VersioningProfile.hasTerminalVersion(pko.getVersionedName()));
// should update in another thread
PublicKeyObject pkoread = new PublicKeyObject(keyName, null); // new handle
Assert.assertTrue(pkoread.available());
Assert.assertEquals(pkoread.getVersionedName(), pko.getVersionedName());
Assert.assertTrue(pkoread.equalsKey(pko));
if (null != optional2ndKey) {
pkoread.setupSave(SaveType.RAW);
Log.info(Log.FAC_TEST, "Reading and writing second raw key " + keyName + " key 1: " + key.getAlgorithm() + " key 2: " + ((null == optional2ndKey) ? "null" : optional2ndKey.getAlgorithm()));
pkoread.save(optional2ndKey);
Assert.assertTrue(VersioningProfile.isLaterVersionOf(pkoread.getVersionedName(), pko.getVersionedName()));
pko.update();
Assert.assertEquals(pkoread.getVersionedName(), pko.getVersionedName());
Assert.assertTrue(pkoread.equalsKey(pko));
Assert.assertTrue(pko.equalsKey(optional2ndKey));
}
Log.info(Log.FAC_TEST, "Finished reading and writing raw key " + keyName + " key 1: " + key.getAlgorithm() + " key 2: " + ((null == optional2ndKey) ? "null" : optional2ndKey.getAlgorithm()));
}
public void testRepoKeyReadWrite(ContentName keyName, PublicKey key, PublicKey optional2ndKey) throws ConfigurationException, IOException, VersionMissingException {
Log.info(Log.FAC_TEST, "Reading and writing key to repo " + keyName + " key 1: " + key.getAlgorithm() + " key 2: " + ((null == optional2ndKey) ? "null" : optional2ndKey.getAlgorithm()));
PublicKeyObject pko = new PublicKeyObject(keyName, key, SaveType.REPOSITORY, handle);
pko.save();
TestUtils.checkObject(handle, pko);
Assert.assertTrue(VersioningProfile.hasTerminalVersion(pko.getVersionedName()));
Log.info(Log.FAC_TEST, "Saved " + pko.getVersionedName() + " to repo, now trying to read.");
// should update in another thread
PublicKeyObject pkoread = new PublicKeyObject(keyName, null); // new handle
Assert.assertTrue(pkoread.available());
Assert.assertEquals(pkoread.getVersionedName(), pko.getVersionedName());
Assert.assertTrue(pkoread.equalsKey(pko));
if (null != optional2ndKey) {
pkoread.setupSave(SaveType.REPOSITORY);
Log.info(Log.FAC_TEST, "Reading and writing second key to repo " + keyName + " key 1: " + key.getAlgorithm() + " key 2: " + ((null == optional2ndKey) ? "null" : optional2ndKey.getAlgorithm()));
pkoread.save(optional2ndKey);
Assert.assertTrue(VersioningProfile.isLaterVersionOf(pkoread.getVersionedName(), pko.getVersionedName()));
pko.update();
Assert.assertEquals(pkoread.getVersionedName(), pko.getVersionedName());
Assert.assertTrue(pkoread.equalsKey(pko));
Assert.assertTrue(pko.equalsKey(optional2ndKey));
}
Log.info(Log.FAC_TEST, "Finished reading and writing key to repo " + keyName + " key 1: " + key.getAlgorithm() + " key 2: " + ((null == optional2ndKey) ? "null" : optional2ndKey.getAlgorithm()));
}
}