/** * Copyright (C) 2014-2017 Regents of the University of California. * @author: Jeff Thompson <jefft0@remap.ucla.edu> * @author: From code in ndn-cxx by Yingdi Yu <yingdi@cs.ucla.edu> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * A copy of the GNU Lesser General Public License is in the file COPYING. */ package net.named_data.jndn.security; import java.io.IOException; import java.nio.ByteBuffer; import java.util.logging.Level; import java.util.logging.Logger; import net.named_data.jndn.Data; import net.named_data.jndn.Face; import net.named_data.jndn.Interest; import net.named_data.jndn.Name; import net.named_data.jndn.OnData; import net.named_data.jndn.OnTimeout; import net.named_data.jndn.Signature; import net.named_data.jndn.encoding.WireFormat; import net.named_data.jndn.encoding.der.DerDecodingException; import net.named_data.jndn.security.certificate.IdentityCertificate; import net.named_data.jndn.security.identity.IdentityManager; import net.named_data.jndn.security.policy.NoVerifyPolicyManager; import net.named_data.jndn.security.policy.PolicyManager; import net.named_data.jndn.util.Blob; import net.named_data.jndn.util.Common; import net.named_data.jndn.util.SignedBlob; /** * KeyChain is the main class of the security library. * * The KeyChain class provides a set of interfaces to the security library such * as identity management, policy configuration and packet signing and * verification. * @note This class is an experimental feature. See the API docs for more * detail at * http://named-data.net/doc/ndn-ccl-api/key-chain.html . */ public class KeyChain { /** * Create a new KeyChain with the given IdentityManager and PolicyManager. * @param identityManager An object of a subclass of IdentityManager. * @param policyManager An object of a subclass of PolicyManager. */ public KeyChain (IdentityManager identityManager, PolicyManager policyManager) { identityManager_ = identityManager; policyManager_ = policyManager; } /** * Create a new KeyChain with the given IdentityManager and a * NoVerifyPolicyManager. * @param identityManager An object of a subclass of IdentityManager. */ public KeyChain(IdentityManager identityManager) { identityManager_ = identityManager; policyManager_ = new NoVerifyPolicyManager(); } /** * Create a new KeyChain with the the default IdentityManager and a * NoVerifyPolicyManager. */ public KeyChain() throws SecurityException { identityManager_ = new IdentityManager(); policyManager_ = new NoVerifyPolicyManager(); } /***************************************** * Identity Management * *****************************************/ /** * Create an identity by creating a pair of Key-Signing-Key (KSK) for this * identity and a self-signed certificate of the KSK. If a key pair or * certificate for the identity already exists, use it. * @param identityName The name of the identity. * @param params The key parameters if a key needs to be generated for the * identity. * @return The name of the default certificate of the identity. * @throws SecurityException if the identity has already been created. */ public final Name createIdentityAndCertificate(Name identityName, KeyParams params) throws SecurityException { return identityManager_.createIdentityAndCertificate(identityName, params); } /** * Create an identity by creating a pair of Key-Signing-Key (KSK) for this * identity and a self-signed certificate of the KSK. Use DEFAULT_KEY_PARAMS * to create the key if needed. If a key pair or certificate for the identity * already exists, use it. * @param identityName The name of the identity. * @return The name of the default certificate of the identity. * @throws SecurityException if the identity has already been created. */ public final Name createIdentityAndCertificate(Name identityName) throws SecurityException { return createIdentityAndCertificate(identityName, DEFAULT_KEY_PARAMS); } /** * Create an identity by creating a pair of Key-Signing-Key (KSK) for this * identity and a self-signed certificate of the KSK. * @deprecated Use createIdentityAndCertificate which returns the * certificate name instead of the key name. * @param identityName The name of the identity. * @param params The key parameters if a key needs to be generated for the * identity. * @return The key name of the auto-generated KSK of the identity. * @throws SecurityException if the identity has already been created. */ public final Name createIdentity(Name identityName, KeyParams params) throws SecurityException { return IdentityCertificate.certificateNameToPublicKeyName (createIdentityAndCertificate(identityName, params)); } /** * Create an identity by creating a pair of Key-Signing-Key (KSK) for this * identity and a self-signed certificate of the KSK. Use DEFAULT_KEY_PARAMS * to create the key if needed. * @deprecated Use createIdentityAndCertificate which returns the * certificate name instead of the key name. * @param identityName The name of the identity. * @return The key name of the auto-generated KSK of the identity. * @throws SecurityException if the identity has already been created. */ public final Name createIdentity(Name identityName) throws SecurityException { return IdentityCertificate.certificateNameToPublicKeyName (createIdentityAndCertificate(identityName)); } /** * Delete the identity from the public and private key storage. If the * identity to be deleted is the current default system default, this will not * delete the identity and will return immediately. * @param identityName The name of the identity. */ public final void deleteIdentity(Name identityName) throws SecurityException { identityManager_.deleteIdentity(identityName); } /** * Get the default identity. * @return The name of default identity. * @throws SecurityException if the default identity is not set. */ public final Name getDefaultIdentity() throws SecurityException { return identityManager_.getDefaultIdentity(); } /** * Get the default certificate name of the default identity. * @return The requested certificate name. * @throws SecurityException if the default identity is not set or the default * key name for the identity is not set or the default certificate name for * the key name is not set. */ public final Name getDefaultCertificateName() throws SecurityException { return identityManager_.getDefaultCertificateName(); } /** * Generate a pair of RSA keys for the specified identity. * @param identityName The name of the identity. * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK). * @param keySize The size of the key. * @return The generated key name. */ public final Name generateRSAKeyPair (Name identityName, boolean isKsk, int keySize) throws SecurityException { return identityManager_.generateRSAKeyPair(identityName, isKsk, keySize); } /** * Generate a pair of RSA keys for the specified identity and default keySize * 2048. * @param identityName The name of the identity. * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK). * @return The generated key name. */ public final Name generateRSAKeyPair(Name identityName, boolean isKsk) throws SecurityException { return identityManager_.generateRSAKeyPair(identityName, isKsk); } /** * Generate a pair of RSA keys for the specified identity for a * Data-Signing-Key and default keySize 2048. * @param identityName The name of the identity. * @return The generated key name. */ public final Name generateRSAKeyPair(Name identityName) throws SecurityException { return identityManager_.generateRSAKeyPair(identityName); } /** * Generate a pair of ECDSA keys for the specified identity. * @param identityName The name of the identity. * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK). * @param keySize The size of the key. * @return The generated key name. */ public final Name generateEcdsaKeyPair (Name identityName, boolean isKsk, int keySize) throws SecurityException { return identityManager_.generateEcdsaKeyPair(identityName, isKsk, keySize); } /** * Generate a pair of ECDSA keys for the specified identity and default keySize * 256. * @param identityName The name of the identity. * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK). * @return The generated key name. */ public final Name generateEcdsaKeyPair(Name identityName, boolean isKsk) throws SecurityException { return identityManager_.generateEcdsaKeyPair(identityName, isKsk); } /** * Generate a pair of ECDSA keys for the specified identity for a * Data-Signing-Key and default keySize 256. * @param identityName The name of the identity. * @return The generated key name. */ public final Name generateEcdsaKeyPair(Name identityName) throws SecurityException { return identityManager_.generateEcdsaKeyPair(identityName); } /** * Set a key as the default key of an identity. The identity name is inferred * from keyName. * @param keyName The name of the key. * @param identityNameCheck The identity name to check that the keyName * contains the same identity name. If an empty name, it is ignored. */ public final void setDefaultKeyForIdentity(Name keyName, Name identityNameCheck) throws SecurityException { identityManager_.setDefaultKeyForIdentity(keyName, identityNameCheck); } /** * Set a key as the default key of an identity. The identity name is inferred * from keyName. * @param keyName The name of the key. */ public final void setDefaultKeyForIdentity(Name keyName) throws SecurityException { identityManager_.setDefaultKeyForIdentity(keyName); } /** * Generate a pair of RSA keys for the specified identity and set it as * default key for the identity. * @param identityName The name of the identity. * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK). * @param keySize The size of the key. * @return The generated key name. */ public final Name generateRSAKeyPairAsDefault (Name identityName, boolean isKsk, int keySize) throws SecurityException { return identityManager_.generateRSAKeyPairAsDefault(identityName, isKsk, keySize); } /** * Generate a pair of RSA keys for the specified identity and set it as * default key for the identity, using the default keySize 2048. * @param identityName The name of the identity. * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK). * @return The generated key name. */ public final Name generateRSAKeyPairAsDefault(Name identityName, boolean isKsk) throws SecurityException { return identityManager_.generateRSAKeyPairAsDefault(identityName, isKsk); } /** * Generate a pair of RSA keys for the specified identity and set it as * default key for the identity for a Data-Signing-Key and using the default * keySize 2048. * @param identityName The name of the identity. * @return The generated key name. */ public final Name generateRSAKeyPairAsDefault(Name identityName) throws SecurityException { return identityManager_.generateRSAKeyPairAsDefault(identityName); } /** * Generate a pair of ECDSA keys for the specified identity and set it as * default key for the identity. * @param identityName The name of the identity. * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK). * @param keySize The size of the key. * @return The generated key name. */ public final Name generateEcdsaKeyPairAsDefault (Name identityName, boolean isKsk, int keySize) throws SecurityException { return identityManager_.generateEcdsaKeyPairAsDefault(identityName, isKsk, keySize); } /** * Generate a pair of ECDSA keys for the specified identity and set it as * default key for the identity, using the default keySize 256. * @param identityName The name of the identity. * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK). * @return The generated key name. */ public final Name generateEcdsaKeyPairAsDefault(Name identityName, boolean isKsk) throws SecurityException { return identityManager_.generateEcdsaKeyPairAsDefault(identityName, isKsk); } /** * Generate a pair of ECDSA keys for the specified identity and set it as * default key for the identity for a Data-Signing-Key and using the default * keySize 256. * @param identityName The name of the identity. * @return The generated key name. */ public final Name generateEcdsaKeyPairAsDefault(Name identityName) throws SecurityException { return identityManager_.generateEcdsaKeyPairAsDefault(identityName); } /** * Create a public key signing request. * @param keyName The name of the key. * @return The signing request data. * @throws SecurityException if the keyName is not found. */ public final Blob createSigningRequest(Name keyName) throws SecurityException { return identityManager_.getPublicKey(keyName).getKeyDer(); } /** * Install an identity certificate into the public key identity storage. * @param certificate The certificate to to added. */ public final void installIdentityCertificate(IdentityCertificate certificate) throws SecurityException { identityManager_.addCertificate(certificate); } /** * Set the certificate as the default for its corresponding key. * @param certificate The certificate. */ public final void setDefaultCertificateForKey(IdentityCertificate certificate) throws SecurityException { identityManager_.setDefaultCertificateForKey(certificate); } /** * Get a certificate with the specified name. * @param certificateName The name of the requested certificate. * @return The requested certificate. */ public final IdentityCertificate getCertificate(Name certificateName) throws SecurityException, DerDecodingException { return identityManager_.getCertificate(certificateName); } /** * @deprecated Use getCertificate. */ public final IdentityCertificate getIdentityCertificate(Name certificateName) throws SecurityException, DerDecodingException { return identityManager_.getCertificate(certificateName); } /** * Revoke a key. * @param keyName The name of the key that will be revoked. */ public final void revokeKey(Name keyName) { //TODO: Implement } /** * Revoke a certificate. * @param certificateName The name of the certificate that will be revoked. */ public final void revokeCertificate(Name certificateName) { //TODO: Implement } /** * Get the identity manager given to or created by the constructor. * @return The identity manager. */ public final IdentityManager getIdentityManager() { return identityManager_; } /***************************************** * Sign/Verify * *****************************************/ /** * Wire encode the Data object, sign it and set its signature. * @param data The Data object to be signed. This updates its signature and * key locator field and wireEncoding. * @param certificateName The certificate name of the key to use for signing. * @param wireFormat A WireFormat object used to encode the input. */ public final void sign(Data data, Name certificateName, WireFormat wireFormat) throws SecurityException { identityManager_.signByCertificate(data, certificateName, wireFormat); } /** * Wire encode the Data object, sign it and set its signature. * Use the default WireFormat.getDefaultWireFormat() * @param data The Data object to be signed. This updates its signature and * key locator field and wireEncoding. * @param certificateName The certificate name of the key to use for signing. */ public final void sign(Data data, Name certificateName) throws SecurityException { sign(data, certificateName, WireFormat.getDefaultWireFormat()); } /** * Wire encode the Data object, sign it with the default identity and set its * signature. * @param data The Data object to be signed. This updates its signature and * key locator field and wireEncoding. * @param wireFormat A WireFormat object used to encode the input. */ public final void sign(Data data, WireFormat wireFormat) throws SecurityException { identityManager_.signByCertificate (data, prepareDefaultCertificateName(), wireFormat); } /** * Wire encode the Data object, sign it with the default identity and set its * signature. * Use the default WireFormat.getDefaultWireFormat() * @param data The Data object to be signed. This updates its signature and * key locator field and wireEncoding. */ public final void sign(Data data) throws SecurityException { sign(data, WireFormat.getDefaultWireFormat()); } /** * Append a SignatureInfo to the Interest name, sign the name components and * append a final name component with the signature bits. * @param interest The Interest object to be signed. This appends name * components of SignatureInfo and the signature bits. * @param certificateName The certificate name of the key to use for signing. * @param wireFormat A WireFormat object used to encode the input. */ public final void sign(Interest interest, Name certificateName, WireFormat wireFormat) throws SecurityException { identityManager_.signInterestByCertificate (interest, certificateName, wireFormat); } /** * Append a SignatureInfo to the Interest name, sign the name components and * append a final name component with the signature bits. * @param interest The Interest object to be signed. This appends name * components of SignatureInfo and the signature bits. * @param certificateName The certificate name of the key to use for signing. */ public final void sign(Interest interest, Name certificateName) throws SecurityException { sign(interest, certificateName, WireFormat.getDefaultWireFormat()); } /** * Append a SignatureInfo to the Interest name, sign the name components with * the default identity and append a final name component with the signature * bits. * @param interest The Interest object to be signed. This appends name * components of SignatureInfo and the signature bits. * @param wireFormat A WireFormat object used to encode the input. */ public final void sign(Interest interest, WireFormat wireFormat) throws SecurityException { identityManager_.signInterestByCertificate (interest, prepareDefaultCertificateName(), wireFormat); } /** * Append a SignatureInfo to the Interest name, sign the name components with * the default identity and append a final name component with the signature * bits. * @param interest The Interest object to be signed. This appends name * components of SignatureInfo and the signature bits. */ public final void sign(Interest interest) throws SecurityException { sign(interest, WireFormat.getDefaultWireFormat()); } /** * Sign the byte buffer using a certificate name and return a Signature object. * @param buffer The byte array to be signed. * @param certificateName The certificate name used to get the signing key and which will be put into KeyLocator. * @return The Signature. */ public Signature sign(ByteBuffer buffer, Name certificateName) throws SecurityException { return identityManager_.signByCertificate(buffer, certificateName); } /** * Wire encode the Data object, sign it and set its signature. * @param data The Data object to be signed. This updates its signature and * key locator field and wireEncoding. * @param identityName The identity name for the key to use for signing. * If empty, infer the signing identity from the data packet name. * @param wireFormat A WireFormat object used to encode the input. If omitted, use WireFormat getDefaultWireFormat(). */ public final void signByIdentity (Data data, Name identityName, WireFormat wireFormat) throws SecurityException { Name signingCertificateName; if (identityName.size() == 0) { Name inferredIdentity = policyManager_.inferSigningIdentity(data.getName()); if (inferredIdentity.size() == 0) signingCertificateName = identityManager_.getDefaultCertificateName(); else signingCertificateName = identityManager_.getDefaultCertificateNameForIdentity(inferredIdentity); } else signingCertificateName = identityManager_.getDefaultCertificateNameForIdentity(identityName); if (signingCertificateName.size() == 0) throw new SecurityException("No qualified certificate name found!"); if (!policyManager_.checkSigningPolicy(data.getName(), signingCertificateName)) throw new SecurityException ("Signing Cert name does not comply with signing policy"); identityManager_.signByCertificate(data, signingCertificateName, wireFormat); } /** * Wire encode the Data object, sign it and set its signature. * @param data The Data object to be signed. This updates its signature and * key locator field and wireEncoding. * Use the default WireFormat.getDefaultWireFormat(). * @param identityName The identity name for the key to use for signing. * If empty, infer the signing identity from the data packet name. */ public final void signByIdentity(Data data, Name identityName) throws SecurityException { signByIdentity(data, identityName, WireFormat.getDefaultWireFormat()); } /** * Wire encode the Data object, sign it and set its signature. * @param data The Data object to be signed. This updates its signature and * key locator field and wireEncoding. * Infer the signing identity from the data packet name. * Use the default WireFormat.getDefaultWireFormat(). */ public final void signByIdentity(Data data) throws SecurityException { signByIdentity(data, new Name(), WireFormat.getDefaultWireFormat()); } /** * Sign the byte buffer using an identity name and return a Signature object. * @param buffer The byte array to be signed. * @param identityName The identity name. * @return The Signature. */ public Signature signByIdentity(ByteBuffer buffer, Name identityName) throws SecurityException { Name signingCertificateName = identityManager_.getDefaultCertificateNameForIdentity(identityName); if (signingCertificateName.size() == 0) throw new SecurityException("No qualified certificate name found!"); return identityManager_.signByCertificate(buffer, signingCertificateName); } /** * Wire encode the Data object, digest it and set its SignatureInfo to * a DigestSha256. * @param data The Data object to be signed. This updates its signature and * wireEncoding. * @param wireFormat A WireFormat object used to encode the input. */ public final void signWithSha256(Data data, WireFormat wireFormat) throws SecurityException { identityManager_.signWithSha256(data, wireFormat); } /** * Wire encode the Data object, digest it and set its SignatureInfo to * a DigestSha256. * @param data The Data object to be signed. This updates its signature and * wireEncoding. */ public final void signWithSha256(Data data) throws SecurityException { signWithSha256(data, WireFormat.getDefaultWireFormat()); } /** * Append a SignatureInfo for DigestSha256 to the Interest name, digest the * name components and append a final name component with the signature bits * (which is the digest). * @param interest The Interest object to be signed. This appends name * components of SignatureInfo and the signature bits. * @param wireFormat A WireFormat object used to encode the input. */ public final void signWithSha256(Interest interest, WireFormat wireFormat) throws SecurityException { identityManager_.signInterestWithSha256(interest, wireFormat); } /** * Append a SignatureInfo for DigestSha256 to the Interest name, digest the * name components and append a final name component with the signature bits * (which is the digest). * @param interest The Interest object to be signed. This appends name * components of SignatureInfo and the signature bits. */ public final void signWithSha256(Interest interest) throws SecurityException { signWithSha256(interest, WireFormat.getDefaultWireFormat()); } public final void verifyData (Data data, OnVerified onVerified, OnDataValidationFailed onValidationFailed, int stepCount) throws SecurityException { Logger.getLogger(this.getClass().getName()).log (Level.INFO, "Enter Verify"); if (policyManager_.requireVerify(data)) { ValidationRequest nextStep = policyManager_.checkVerificationPolicy (data, stepCount, onVerified, onValidationFailed); if (nextStep != null) { VerifyCallbacks callbacks = new VerifyCallbacks (nextStep, nextStep.retry_, onValidationFailed, data); try { face_.expressInterest(nextStep.interest_, callbacks, callbacks); } catch (IOException ex) { try { onValidationFailed.onDataValidationFailed (data, "Error calling expressInterest " + ex); } catch (Throwable exception) { logger_.log(Level.SEVERE, "Error in onDataValidationFailed", exception); } } } } else if (policyManager_.skipVerifyAndTrust(data)) { try { onVerified.onVerified(data); } catch (Throwable ex) { logger_.log(Level.SEVERE, "Error in onVerified", ex); } } else { try { onValidationFailed.onDataValidationFailed (data, "The packet has no verify rule but skipVerifyAndTrust is false"); } catch (Throwable ex) { logger_.log(Level.SEVERE, "Error in onDataValidationFailed", ex); } } } /** * Check the signature on the Data object and call either onVerify.onVerify or * onValidationFailed.onDataValidationFailed. * We use callback functions because verify may fetch information to check the * signature. * @param data The Data object with the signature to check. It is an error if * data does not have a wireEncoding. * To set the wireEncoding, you can call data.wireDecode. * @param onVerified If the signature is verified, this calls * onVerified.onVerified(data). * NOTE: The library will log any exceptions thrown by this callback, but for * better error handling the callback should catch and properly handle any * exceptions. * @param onValidationFailed If the signature check fails, this calls * onValidationFailed.onDataValidationFailed(data, reason). * NOTE: The library will log any exceptions thrown by this callback, but for * better error handling the callback should catch and properly handle any * exceptions. */ public final void verifyData (Data data, OnVerified onVerified, OnDataValidationFailed onValidationFailed) throws SecurityException { verifyData(data, onVerified, onValidationFailed, 0); } /** * Check the signature on the Data object and call either onVerify.onVerify or * onVerifyFailed.onVerifyFailed. * We use callback functions because verify may fetch information to check the * signature. * @deprecated Use verifyData with OnDataValidationFailed. * @param data The Data object with the signature to check. It is an error if * data does not have a wireEncoding. * To set the wireEncoding, you can call data.wireDecode. * @param onVerified If the signature is verified, this calls * onVerified.onVerified(data). * NOTE: The library will log any exceptions thrown by this callback, but for * better error handling the callback should catch and properly handle any * exceptions. * @param onVerifyFailed If the signature check fails, this calls * onVerifyFailed.onVerifyFailed(data). * NOTE: The library will log any exceptions thrown by this callback, but for * better error handling the callback should catch and properly handle any * exceptions. */ public final void verifyData (Data data, OnVerified onVerified, final OnVerifyFailed onVerifyFailed) throws SecurityException { // Wrap the onVerifyFailed in an OnDataValidationFailed. verifyData (data, onVerified, new OnDataValidationFailed() { public void onDataValidationFailed(Data localData, String reason) { onVerifyFailed.onVerifyFailed(localData); } }); } public final void verifyInterest (Interest interest, OnVerifiedInterest onVerified, OnInterestValidationFailed onValidationFailed, int stepCount) throws SecurityException { Logger.getLogger(this.getClass().getName()).log (Level.INFO, "Enter Verify"); if (policyManager_.requireVerify(interest)) { ValidationRequest nextStep = policyManager_.checkVerificationPolicy (interest, stepCount, onVerified, onValidationFailed); if (nextStep != null) { VerifyCallbacksForVerifyInterest callbacks = new VerifyCallbacksForVerifyInterest (nextStep, nextStep.retry_, onValidationFailed, interest); try { face_.expressInterest(nextStep.interest_, callbacks, callbacks); } catch (IOException ex) { try { onValidationFailed.onInterestValidationFailed (interest, "Error calling expressInterest " + ex); } catch (Throwable exception) { logger_.log(Level.SEVERE, "Error in onInterestValidationFailed", exception); } } } } else if (policyManager_.skipVerifyAndTrust(interest)) { try { onVerified.onVerifiedInterest(interest); } catch (Throwable ex) { logger_.log(Level.SEVERE, "Error in onVerifiedInterest", ex); } } else { try { onValidationFailed.onInterestValidationFailed (interest, "The packet has no verify rule but skipVerifyAndTrust is false"); } catch (Throwable ex) { logger_.log(Level.SEVERE, "Error in onInterestValidationFailed", ex); } } } /** * Check the signature on the signed interest and call either * onVerify.onVerifiedInterest or * onValidationFailed.onInterestValidationFailed. We * use callback functions because verify may fetch information to check the * signature. * @param interest The interest with the signature to check. * @param onVerified If the signature is verified, this calls * onVerified.onVerifiedInterest(interest). * NOTE: The library will log any exceptions thrown by this callback, but for * better error handling the callback should catch and properly handle any * exceptions. * @param onValidationFailed If the signature check fails, this calls * onValidationFailed.onInterestValidationFailed(interest, reason). * NOTE: The library will log any exceptions thrown by this callback, but for * better error handling the callback should catch and properly handle any * exceptions. */ public final void verifyInterest (Interest interest, OnVerifiedInterest onVerified, OnInterestValidationFailed onValidationFailed) throws SecurityException { verifyInterest(interest, onVerified, onValidationFailed, 0); } /** * Check the signature on the signed interest and call either * onVerify.onVerifiedInterest or onVerifyFailed.onVerifyInterestFailed. We * use callback functions because verify may fetch information to check the * signature. * @deprecated Use verifyInterest with OnInterestValidationFailed. * @param interest The interest with the signature to check. * @param onVerified If the signature is verified, this calls * onVerified.onVerifiedInterest(interest). * NOTE: The library will log any exceptions thrown by this callback, but for * better error handling the callback should catch and properly handle any * exceptions. * @param onVerifyFailed If the signature check fails, this calls * onVerifyFailed.onVerifyInterestFailed(interest). * NOTE: The library will log any exceptions thrown by this callback, but for * better error handling the callback should catch and properly handle any * exceptions. */ public final void verifyInterest (Interest interest, OnVerifiedInterest onVerified, final OnVerifyInterestFailed onVerifyFailed) throws SecurityException { // Wrap the onVerifyFailed in an OnInterestValidationFailed. verifyInterest (interest, onVerified, new OnInterestValidationFailed() { public void onInterestValidationFailed (Interest localInterest, String reason) { onVerifyFailed.onVerifyInterestFailed(localInterest); } }); } /** * Set the Face which will be used to fetch required certificates. * @param face The Face object. */ public final void setFace(Face face) { face_ = face; } /** * Wire encode the data packet, compute an HmacWithSha256 and update the * signature value. * @note This method is an experimental feature. The API may change. * @param data The Data object to be signed. This updates its signature. * @param key The key for the HmacWithSha256. * @param wireFormat A WireFormat object used to encode the data packet. */ public static void signWithHmacWithSha256(Data data, Blob key, WireFormat wireFormat) { // Encode once to get the signed portion. SignedBlob encoding = data.wireEncode(wireFormat); byte[] signatureBytes = Common.computeHmacWithSha256 (key.getImmutableArray(), encoding.signedBuf()); data.getSignature().setSignature(new Blob(signatureBytes, false)); } /** * Wire encode the data packet, compute an HmacWithSha256 and update the * signature value. * Use the default WireFormat.getDefaultWireFormat(). * @note This method is an experimental feature. The API may change. * @param data The Data object to be signed. This updates its signature. * @param key The key for the HmacWithSha256. */ public static void signWithHmacWithSha256(Data data, Blob key) { signWithHmacWithSha256(data, key, WireFormat.getDefaultWireFormat()); } /** * Compute a new HmacWithSha256 for the data packet and verify it against the * signature value. * @note This method is an experimental feature. The API may change. * @param data The Data packet to verify. * @param key The key for the HmacWithSha256. * @param wireFormat A WireFormat object used to encode the data packet. * @return True if the signature verifies, otherwise false. */ public static boolean verifyDataWithHmacWithSha256(Data data, Blob key, WireFormat wireFormat) { // wireEncode returns the cached encoding if available. SignedBlob encoding = data.wireEncode(wireFormat); byte[] newSignatureBytes = Common.computeHmacWithSha256 (key.getImmutableArray(), encoding.signedBuf()); return ByteBuffer.wrap(newSignatureBytes).equals (data.getSignature().getSignature().buf()); } /** * Compute a new HmacWithSha256 for the data packet and verify it against the * signature value. * Use the default WireFormat.getDefaultWireFormat(). * @note This method is an experimental feature. The API may change. * @param data The Data packet to verify. * @param key The key for the HmacWithSha256. * @return True if the signature verifies, otherwise false. */ public static boolean verifyDataWithHmacWithSha256(Data data, Blob key) { return verifyDataWithHmacWithSha256 (data, key, WireFormat.getDefaultWireFormat()); } public static final RsaKeyParams DEFAULT_KEY_PARAMS = new RsaKeyParams(); /** * A VerifyCallbacks is used for callbacks from verifyData. */ private class VerifyCallbacks implements OnData, OnTimeout { public VerifyCallbacks (ValidationRequest nextStep, int retry, OnDataValidationFailed onValidationFailed, Data originalData) { nextStep_ = nextStep; retry_ = retry; onValidationFailed_ = onValidationFailed; originalData_ = originalData; } public final void onData(Interest interest, Data data) { try { // Try to verify the certificate (data) according to the parameters in // nextStep. verifyData (data, nextStep_.onVerified_, nextStep_.onValidationFailed_, nextStep_.stepCount_); } catch (SecurityException ex) { Logger.getLogger(KeyChain.class.getName()).log(Level.SEVERE, null, ex); } } public final void onTimeout(Interest interest) { if (retry_ > 0) { // Issue the same expressInterest as in verifyData except decrement // retry. VerifyCallbacks callbacks = new VerifyCallbacks (nextStep_, retry_ - 1, onValidationFailed_, originalData_); try { face_.expressInterest(interest, callbacks, callbacks); } catch (IOException ex) { try { onValidationFailed_.onDataValidationFailed (originalData_, "Error in expressInterest to retry after timeout for fetching " + interest.getName().toUri() + ": " + ex); } catch (Throwable exception) { logger_.log(Level.SEVERE, "Error in onDataValidationFailed", exception); } } } else { try { onValidationFailed_.onDataValidationFailed (originalData_, "The retry count is zero after timeout for fetching " + interest.getName().toUri()); } catch (Throwable ex) { logger_.log(Level.SEVERE, "Error in onDataValidationFailed", ex); } } } private final ValidationRequest nextStep_; private final int retry_; private final OnDataValidationFailed onValidationFailed_; private final Data originalData_; } /** * A VerifyCallbacksForVerifyInterest is used for callbacks from verifyInterest. * This is the same as VerifyCallbacks, but we call * onValidationFailed.onInterestValidationFailed(originalInterest, reason) if * we have too many retries. */ private class VerifyCallbacksForVerifyInterest implements OnData, OnTimeout { public VerifyCallbacksForVerifyInterest (ValidationRequest nextStep, int retry, OnInterestValidationFailed onValidationFailed, Interest originalInterest) { nextStep_ = nextStep; retry_ = retry; onValidationFailed_ = onValidationFailed; originalInterest_ = originalInterest; } public final void onData(Interest interest, Data data) { try { // Try to verify the certificate (data) according to the parameters in // nextStep. verifyData (data, nextStep_.onVerified_, nextStep_.onValidationFailed_, nextStep_.stepCount_); } catch (SecurityException ex) { Logger.getLogger(KeyChain.class.getName()).log(Level.SEVERE, null, ex); } } public final void onTimeout(Interest interest) { if (retry_ > 0) { // Issue the same expressInterest as in verifyData except decrement // retry. VerifyCallbacksForVerifyInterest callbacks = new VerifyCallbacksForVerifyInterest (nextStep_, retry_ - 1, onValidationFailed_, originalInterest_); try { face_.expressInterest(interest, callbacks, callbacks); } catch (IOException ex) { try { onValidationFailed_.onInterestValidationFailed (originalInterest_, "Error in expressInterest to retry after timeout for fetching " + interest.getName().toUri() + ": " + ex); } catch (Throwable exception) { logger_.log(Level.SEVERE, "Error in onInterestValidationFailed", exception); } } } else { try { onValidationFailed_.onInterestValidationFailed (originalInterest_, "The retry count is zero after timeout for fetching " + interest.getName().toUri()); } catch (Throwable ex) { logger_.log(Level.SEVERE, "Error in onInterestValidationFailed", ex); } } } private final ValidationRequest nextStep_; private final int retry_; private final OnInterestValidationFailed onValidationFailed_; private final Interest originalInterest_; } /** * Get the default certificate from the identity storage and return its name. * If there is no default identity or default certificate, then create one. * @return The default certificate name. */ private Name prepareDefaultCertificateName() throws SecurityException { IdentityCertificate signingCertificate = identityManager_.getDefaultCertificate(); if (signingCertificate == null) { setDefaultCertificate(); signingCertificate = identityManager_.getDefaultCertificate(); } return signingCertificate.getName(); } /** * Create the default certificate if it is not initialized. If there is no * default identity yet, creating a new tmp-identity. */ private void setDefaultCertificate() throws SecurityException { if (identityManager_.getDefaultCertificate() == null) { Name defaultIdentity; try { defaultIdentity = identityManager_.getDefaultIdentity(); } catch (SecurityException e) { // Create a default identity name. ByteBuffer randomComponent = ByteBuffer.allocate(4); Common.getRandom().nextBytes(randomComponent.array()); defaultIdentity = new Name().append("tmp-identity") .append(new Blob(randomComponent, false)); } createIdentityAndCertificate(defaultIdentity); identityManager_.setDefaultIdentity(defaultIdentity); } } private final IdentityManager identityManager_; private final PolicyManager policyManager_; private Face face_ = null; private static final Logger logger_ = Logger.getLogger(KeyChain.class.getName()); }