KeyStore implemented
diff --git a/js/tools/build/ndn-js-uncomp.js b/js/tools/build/ndn-js-uncomp.js
index 6f0cd3e..0a291f1 100644
--- a/js/tools/build/ndn-js-uncomp.js
+++ b/js/tools/build/ndn-js-uncomp.js
@@ -110,6 +110,29 @@
 	this.port=port;
 }
 
+
+NDN.KeyStore = new Array();
+
+var KeyStoreEntry = function KeyStoreEntry(name, key, rsa) {
+	this.keyName = name;  // KeyName
+	this.keyHex = key;    // Raw key hex string
+	this.rsaKey = rsa;    // RSA key
+};
+
+NDN.getKeyByName = function(/* KeyName */ name) {
+	var result = null;
+	
+	for (var i = 0; i < NDN.KeyStore.length; i++) {
+		if (NDN.KeyStore[i].keyName.matches_name(name.contentName)) {
+            if (result == null || 
+                NDN.KeyStore[i].keyName.contentName.components.length > result.keyName.contentName.components.length)
+                result = NDN.KeyStore[i];
+        }
+	}
+    
+	return result;
+};
+
 // For fetching data
 NDN.PITTable = new Array();
 
@@ -407,7 +430,7 @@
 						// Key verification
 						var verified = false;
 						
-						// Recursive key fetching closure
+						// Recursive key fetching & verification closure
 						var KeyFetchClosure = function KeyFetchClosure(content, closure, key, signature) {
 							this.contentObject = content;  // unverified content object
 							this.closure = closure;  // closure corresponding to the contentObject
@@ -421,7 +444,7 @@
 							if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
 								console.log("In KeyFetchClosure.upcall: interest time out.");
 							} else if (kind == Closure.UPCALL_CONTENT) {
-								console.log("In KeyFetchClosure.upcall");
+								console.log("In KeyFetchClosure.upcall: signature verification passed");
 								var keyHex = DataUtils.toHex(upcallInfo.contentObject.content).toLowerCase();
 								console.log("Key: " + keyHex);
 								
@@ -430,7 +453,7 @@
 								
 								var rsakey = new RSAKey();
 								rsakey.setPublic(kp, exp);
-								verified = rsakey.verifyByteArray(this.contentObject.rawSignatureData, sigHex);
+								var verified = rsakey.verifyByteArray(this.contentObject.rawSignatureData, this.signature);
 								var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
 								
 								console.log("raise encapsulated closure");
@@ -448,19 +471,51 @@
 								var keyname = keylocator.keyName.contentName.getName();
 								console.log(keyname);
 								
-								if (nameStr.match("/ccnx.org/Users/")) {
-									console.log("Key found");
-									currentClosure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(ndn, null, 0, co));
+								if (nameStr.match(keyname)) {
+									console.log("Content is key itself");
+									
+									var keyHex = DataUtils.toHex(co.content).toLowerCase();
+									console.log("Key content: " + keyHex);
+									
+									var kp = keyHex.slice(56, 314);
+									var exp = keyHex.slice(318, 324);
+									
+									var rsakey = new RSAKey();
+									rsakey.setPublic(kp, exp);
+									var verified = rsakey.verifyByteArray(co.rawSignatureData, sigHex);
+									var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
+									
+									currentClosure.upcall(flag, new UpcallInfo(ndn, null, 0, co));
+									
+									// Store key in cache
+									var keyEntry = new KeyStoreEntry(keylocator.keyName, keyHex, rsakey);
+									NDN.KeyStore.push(keyEntry);
 								} else {
 									console.log("Fetch key according to keylocator");
-									var nextClosure = new KeyFetchClosure(co, currentClosure, keyname, sigHex);
-									var interest = new Interest(keylocator.keyName.contentName.getPrefix(4));
-									interest.interestLifetime = 4.0;
-									self.expressInterest(ndn, interest, nextClosure);
+									
+									// Check local key store
+									var keyEntry = NDN.getKeyByName(keylocator.keyName);
+									if (keyEntry) {
+										// Key found, verify now
+										console.log("Local key cache hit");
+										var rsakey = keyEntry.rsaKey;
+										verified = rsakey.verifyByteArray(co.rawSignatureData, sigHex);
+										
+										var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
+										
+										// Raise callback
+										currentClosure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(ndn, null, 0, co));
+									} else {
+										// Not found, fetch now
+										var nextClosure = new KeyFetchClosure(co, currentClosure, keyname, sigHex);
+										var interest = new Interest(keylocator.keyName.contentName.getPrefix(4));
+										interest.interestLifetime = 4.0;
+										self.expressInterest(ndn, interest, nextClosure);
+									}
 								}
 							} else if (keylocator.type == KeyLocatorType.KEY) {
 								console.log("Keylocator contains KEY");
-								var publickeyHex = DataUtils.toHex(co.signedInfo.locator.publicKey).toLowerCase();
+								var publickeyHex = DataUtils.toHex(keylocator.publicKey).toLowerCase();
 								console.log(publickeyHex);
 		
 								var kp = publickeyHex.slice(56, 314);
@@ -474,6 +529,10 @@
 								
 								// Raise callback
 								currentClosure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(ndn, null, 0, co));
+								
+								// Store key in cache
+								var keyEntry = new KeyStoreEntry(keylocator.keyName, publickeyHex, rsakey);
+								NDN.KeyStore.push(keyEntry);
 							} else {
 								var cert = keylocator.certificate;
 								console.log("KeyLocator contains CERT");
@@ -2022,94 +2081,94 @@
 
 KeyLocator.prototype.from_ccnb = function(decoder) {
 
-		decoder.readStartElement(this.getElementLabel());
+	decoder.readStartElement(this.getElementLabel());
 
-		if (decoder.peekStartElement(CCNProtocolDTags.Key)) {
-			try {
-				encodedKey = decoder.readBinaryElement(CCNProtocolDTags.Key);
-				// This is a DER-encoded SubjectPublicKeyInfo.
-				
-				//TODO FIX THIS, This should create a Key Object instead of keeping bytes
-
-				this.publicKey =   encodedKey;//CryptoUtil.getPublicKey(encodedKey);
-				this.type = KeyLocatorType.KEY;
-				
-
-				if(LOG>4) console.log('PUBLIC KEY FOUND: '+ this.publicKey);
-				//this.publicKey = encodedKey;
-				
-				
-			} catch (e) {
-				throw new Error("Cannot parse key: ", e);
-			} 
-
-			if (null == this.publicKey) {
-				throw new Error("Cannot parse key: ");
-			}
-
-		} else if ( decoder.peekStartElement(CCNProtocolDTags.Certificate)) {
-			try {
-				encodedCert = decoder.readBinaryElement(CCNProtocolDTags.Certificate);
-				
-				/*
-				 * Certificates not yet working
-				 */
-				
-				//CertificateFactory factory = CertificateFactory.getInstance("X.509");
-				//this.certificate = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(encodedCert));
-				
-
-				this.certificate = encodedCert;
-				this.type = KeyLocatorType.CERTIFICATE;
-
-				if(LOG>4) console.log('CERTIFICATE FOUND: '+ this.certificate);
-				
-			} catch ( e) {
-				throw new Error("Cannot decode certificate: " +  e);
-			}
-			if (null == this.certificate) {
-				throw new Error("Cannot parse certificate! ");
-			}
-		} else  {
-			this.type = KeyLocatorType.KEYNAME;
+	if (decoder.peekStartElement(CCNProtocolDTags.Key)) {
+		try {
+			encodedKey = decoder.readBinaryElement(CCNProtocolDTags.Key);
+			// This is a DER-encoded SubjectPublicKeyInfo.
 			
-			this.keyName = new KeyName();
-			this.keyName.from_ccnb(decoder);
+			//TODO FIX THIS, This should create a Key Object instead of keeping bytes
+
+			this.publicKey =   encodedKey;//CryptoUtil.getPublicKey(encodedKey);
+			this.type = KeyLocatorType.KEY;
+			
+
+			if(LOG>4) console.log('PUBLIC KEY FOUND: '+ this.publicKey);
+			//this.publicKey = encodedKey;
+			
+			
+		} catch (e) {
+			throw new Error("Cannot parse key: ", e);
+		} 
+
+		if (null == this.publicKey) {
+			throw new Error("Cannot parse key: ");
 		}
-		decoder.readEndElement();
+
+	} else if ( decoder.peekStartElement(CCNProtocolDTags.Certificate)) {
+		try {
+			encodedCert = decoder.readBinaryElement(CCNProtocolDTags.Certificate);
+			
+			/*
+			 * Certificates not yet working
+			 */
+			
+			//CertificateFactory factory = CertificateFactory.getInstance("X.509");
+			//this.certificate = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(encodedCert));
+			
+
+			this.certificate = encodedCert;
+			this.type = KeyLocatorType.CERTIFICATE;
+
+			if(LOG>4) console.log('CERTIFICATE FOUND: '+ this.certificate);
+			
+		} catch ( e) {
+			throw new Error("Cannot decode certificate: " +  e);
+		}
+		if (null == this.certificate) {
+			throw new Error("Cannot parse certificate! ");
+		}
+	} else  {
+		this.type = KeyLocatorType.KEYNAME;
+		
+		this.keyName = new KeyName();
+		this.keyName.from_ccnb(decoder);
 	}
+	decoder.readEndElement();
+};
 	
 
-	KeyLocator.prototype.to_ccnb = function( encoder) {
-		
-		if(LOG>4) console.log('type is is ' + this.type);
-		//TODO Check if Name is missing
-		if (!this.validate()) {
-			throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
-		}
+KeyLocator.prototype.to_ccnb = function( encoder) {
+	
+	if(LOG>4) console.log('type is is ' + this.type);
+	//TODO Check if Name is missing
+	if (!this.validate()) {
+		throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
+	}
 
+	
+	//TODO FIX THIS TOO
+	encoder.writeStartElement(this.getElementLabel());
+	
+	if (this.type == KeyLocatorType.KEY) {
+		if(LOG>5)console.log('About to encode a public key' +this.publicKey);
+		encoder.writeElement(CCNProtocolDTags.Key, this.publicKey);
 		
-		//TODO FIX THIS TOO
-		encoder.writeStartElement(this.getElementLabel());
+	} else if (this.type == KeyLocatorType.CERTIFICATE) {
 		
-		if (this.type == KeyLocatorType.KEY) {
-			if(LOG>5)console.log('About to encode a public key' +this.publicKey);
-			encoder.writeElement(CCNProtocolDTags.Key, this.publicKey);
-			
-		} else if (this.type == KeyLocatorType.CERTIFICATE) {
-			
-			try {
-				encoder.writeElement(CCNProtocolDTags.Certificate, this.certificate);
-			} catch ( e) {
-				throw new Error("CertificateEncodingException attempting to write key locator: " + e);
-			}
-			
-		} else if (this.type == KeyLocatorType.KEYNAME) {
-			
-			this.keyName.to_ccnb(encoder);
+		try {
+			encoder.writeElement(CCNProtocolDTags.Certificate, this.certificate);
+		} catch ( e) {
+			throw new Error("CertificateEncodingException attempting to write key locator: " + e);
 		}
-		encoder.writeEndElement();
 		
+	} else if (this.type == KeyLocatorType.KEYNAME) {
+		
+		this.keyName.to_ccnb(encoder);
+	}
+	encoder.writeEndElement();
+	
 };
 
 KeyLocator.prototype.getElementLabel = function() {
@@ -2170,6 +2229,24 @@
 		// null signedInfo ok
 		return (null != this.contentName);
 };
+
+KeyName.prototype.matches_name = function(/*Name*/ name) {
+	var i_name = this.contentName.components;
+	var o_name = name.components;
+
+	// The intrest name is longer than the name we are checking it against.
+	if (i_name.length > o_name.length)
+            return false;
+
+	// Check if at least one of given components doesn't match.
+        for (var i = 0; i < i_name.length; ++i) {
+            if (!DataUtils.arraysEqual(i_name[i], o_name[i]))
+                return false;
+        }
+
+	return true;
+}
+
 /**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.