/**
* Copyright (C) 2017-2018 Regents of the University of California.
* @author: Jeff Thompson <[email protected]>
* @author: From ndn-cxx security https://github.com/named-data/ndn-cxx/blob/master/src/security/pib/pib-memory.cpp
*
* 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.
*/
/** @ignore */
var Name = require('../../name.js').Name; /** @ignore */
var Blob = require('../../util/blob.js').Blob; /** @ignore */
var CertificateV2 = require('../v2/certificate-v2.js').CertificateV2; /** @ignore */
var Pib = require('./pib.js').Pib; /** @ignore */
var PibKey = require('./pib-key.js').PibKey; /** @ignore */
var SyncPromise = require('../../util/sync-promise.js').SyncPromise; /** @ignore */
var PibImpl = require('./pib-impl.js').PibImpl;
/**
* PibMemory extends PibImpl and is used by the Pib class as an in-memory
* implementation of a PIB. All the contents in the PIB are stored in memory and
* have the same lifetime as the PibMemory instance.
* @constructor
*/
var PibMemory = function PibMemory()
{
// Call the base constructor.
PibImpl.call(this);
this.tpmLocator_ = "";
this.defaultIdentityName_ = null;
// Set of Name.
this.identityNames_ = [];
// identityName URI string => default key Name.
// (Use a string because we can't use the Name object as the key in JavaScript.)
this.defaultKeyNames_ = {};
// keyName URI string => keyBits Blob.
// (Use a string because we can't use the Name object as the key in JavaScript.)
this.keys_ = {};
// keyName URI string => default certificate Name.
// (Use a string because we can't use the Name object as the key in JavaScript.)
this.defaultCertificateNames_ = {};
// certificateName URI string => CertificateV2.
// (Use a string because we can't use the Name object as the key in JavaScript.)
this.certificates_ = {};
};
PibMemory.prototype = new PibImpl();
PibMemory.prototype.name = "PibMemory";
exports.PibMemory = PibMemory;
PibMemory.getScheme = function() { return "pib-memory"; }
// TpmLocator management.
/**
* Set the corresponding TPM information to tpmLocator. This method does not
* reset the contents of the PIB.
* @param {string} tpmLocator The TPM locator string.
* @return {SyncPromise} A promise which fulfills when the TPM locator is set.
*/
PibMemory.prototype.setTpmLocatorPromise = function(tpmLocator)
{
this.tpmLocator_ = tpmLocator;
return SyncPromise.resolve();
};
/**
* Get the TPM Locator.
* @return {SyncPromise} A promise which returns the TPM locator string.
*/
PibMemory.prototype.getTpmLocatorPromise = function()
{
return SyncPromise.resolve(this.tpmLocator_);
};
// Identity management.
/**
* Check for the existence of an identity.
* @param {Name} identityName The name of the identity.
* @return {SyncPromise} A promise which returns true if the identity exists,
* otherwise false.
*/
PibMemory.prototype.hasIdentityPromise = function(identityName)
{
return SyncPromise.resolve(this.hasIdentity_(identityName));
};
/**
* Do the work of hasIdentityPromise.
*/
PibMemory.prototype.hasIdentity_ = function(identityName)
{
for (var i in this.identityNames_) {
var name = this.identityNames_[i];
if (name.equals(identityName))
return true;
}
return false;
};
/**
* Add the identity. If the identity already exists, do nothing. If no default
* identity has been set, set the added identity as the default.
* @param {Name} identityName The name of the identity to add. This copies the
* name.
* @return {SyncPromise} A promise which fulfills when the identity is added.
*/
PibMemory.prototype.addIdentityPromise = function(identityName)
{
this.addIdentity_(identityName);
return SyncPromise.resolve();
};
/**
* Do the work of addIdentityPromise.
*/
PibMemory.prototype.addIdentity_ = function(identityName)
{
var identityNameCopy = new Name(identityName);
if (!this.hasIdentity_(identityNameCopy))
this.identityNames_.push(identityNameCopy);
if (this.defaultIdentityName_ === null)
this.defaultIdentityName_ = identityNameCopy;
};
/**
* Remove the identity and its related keys and certificates. If the default
* identity is being removed, no default identity will be selected. If the
* identity does not exist, do nothing.
* @param {Name} identityName The name of the identity to remove.
* @return {SyncPromise} A promise which fulfills when the identity is removed.
*/
PibMemory.prototype.removeIdentityPromise = function(identityName)
{
// Go backwards through the list so we can remove entries.
for (var i = this.identityNames_.length - 1; i >= 0; --i) {
if (this.identityNames_[i].equals(identityName))
this.identityNames_.splice(i, 1);
}
if (this.defaultIdentityName_ !== null &&
identityName.equals(this.defaultIdentityName_))
this.defaultIdentityName_ = null;
var keyNames = this.getKeysOfIdentity_(identityName);
for (var i in keyNames)
this.removeKey_(keyNames[i]);
return SyncPromise.resolve();
};
/**
* Erase all certificates, keys, and identities.
* @return {SyncPromise} A promise which fulfills when the identities are cleared.
*/
PibMemory.prototype.clearIdentitiesPromise = function()
{
this.defaultIdentityName_ = null;
this.identityNames_ = [];
this.defaultKeyNames_ = {};
this.keys_ = {};
this.defaultCertificateNames_ = {};
this.certificates_ = {};
return SyncPromise.resolve();
};
/**
* Get the names of all the identities.
* @return {SyncPromise} A promise which returns a fresh set of identity names
* as an array of Name. The Name objects are fresh copies.
*/
PibMemory.prototype.getIdentitiesPromise = function()
{
// Copy the Name objects.
var result = [];
for (var i in this.identityNames_) {
var name = this.identityNames_[i];
result.push(new Name(name));
}
return SyncPromise.resolve(result);
};
/**
* Set the identity with the identityName as the default identity. If the
* identity with identityName does not exist, then it will be created.
* @param {Name} identityName The name for the default identity. This copies the
* name.
* @return {SyncPromise} A promise which fulfills when the default identity is
* set.
*/
PibMemory.prototype.setDefaultIdentityPromise = function(identityName)
{
this.addIdentity_(identityName);
// Copy the name.
this.defaultIdentityName_ = new Name(identityName);
return SyncPromise.resolve();
};
/**
* Get the default identity.
* @return {SyncPromise} A promise which returns the Name of the default
* identity as a fresh copy, or a promise rejected with Pib.Error for no default
* identity.
*/
PibMemory.prototype.getDefaultIdentityPromise = function()
{
if (this.defaultIdentityName_ !== null)
// Copy the name.
return SyncPromise.resolve(new Name(this.defaultIdentityName_));
return SyncPromise.reject(new Pib.Error(new Error("No default identity")));
};
// Key management.
/**
* Check for the existence of a key with keyName.
* @param {Name} keyName The name of the key.
* @return {SyncPromise} A promise which returns true if the key exists,
* otherwise false. Return false if the identity does not exist.
*/
PibMemory.prototype.hasKeyPromise = function(keyName)
{
return SyncPromise.resolve(this.hasKey_(keyName));
};
/**
* Do the work of hasKeyPromise.
*/
PibMemory.prototype.hasKey_ = function(keyName)
{
return keyName.toUri() in this.keys_;
};
/**
* Add the key. If a key with the same name already exists, overwrite the key.
* If the identity does not exist, it will be created. If no default key for the
* identity has been set, then set the added key as the default for the
* identity. If no default identity has been set, identity becomes the default.
* @param {Name} identityName The name of the identity that the key belongs to.
* This copies the name.
* @param {Name} keyName The name of the key. This copies the name.
* @param {Buffer} key The public key bits. This copies the array.
* @return {SyncPromise} A promise which fulfills when the key is added.
*/
PibMemory.prototype.addKeyPromise = function(identityName, keyName, key)
{
this.addKey_(identityName, keyName, key);
return SyncPromise.resolve();
};
/**
* Do the work of addKeyPromise,
*/
PibMemory.prototype.addKey_ = function(identityName, keyName, key)
{
this.addIdentity_(identityName);
var keyNameCopy = new Name(keyName);
this.keys_[keyNameCopy.toUri()] = new Blob(key, true);
var identityNameUri = identityName.toUri();
if (!(identityNameUri in this.defaultKeyNames_))
this.defaultKeyNames_[identityNameUri] = keyNameCopy;
};
/**
* Remove the key with keyName and its related certificates. If the key does not
* exist, do nothing.
* @param {Name} keyName The name of the key.
* @return {SyncPromise} A promise which fulfills when the key is removed.
*/
PibMemory.prototype.removeKeyPromise = function(keyName)
{
this.removeKey_(keyName);
return SyncPromise.resolve();
};
/**
* Do the work of removeKeyPromise.
*/
PibMemory.prototype.removeKey_ = function(keyName)
{
var identityName = PibKey.extractIdentityFromKeyName(keyName);
delete this.keys_[keyName.toUri()];
delete this.defaultKeyNames_[identityName.toUri()];
var certificateNames = this.getCertificatesOfKey_(keyName);
for (var i in certificateNames)
this.removeCertificate_(certificateNames[i]);
};
/**
* Get the key bits of a key with name keyName.
* @param {Name} keyName The name of the key.
* @return {SyncPromise} A promise which returns the key bits as a Blob, or a
* promise rejected with Pib.Error if the key does not exist.
*/
PibMemory.prototype.getKeyBitsPromise = function(keyName)
{
if (!this.hasKey_(keyName))
return SyncPromise.reject(new Pib.Error(new Error
("Key `" + keyName.toUri() + "` not found")));
var key = this.keys_[keyName.toUri()];
return SyncPromise.resolve(key);
};
/**
* Get all the key names of the identity with the name identityName. The
* returned key names can be used to create a KeyContainer. With a key name and
* a backend implementation, one can create a Key front end instance.
* @param {Name} identityName The name of the identity.
* @return SyncPromise} A promise which returns the set of key names as an array
* of Name. The Name objects are fresh copies. If the identity does not exist,
* return an empty array.
*/
PibMemory.prototype.getKeysOfIdentityPromise = function(identityName)
{
return SyncPromise.resolve(this.getKeysOfIdentity_(identityName));
};
/**
* Do the work of getKeysOfIdentityPromise
*/
PibMemory.prototype.getKeysOfIdentity_ = function(identityName)
{
var ids = [];
for (var keyNameUri in this.keys_) {
var keyName = new Name(keyNameUri);
if (identityName.equals(PibKey.extractIdentityFromKeyName(keyName)))
// keyName is already a copy created from the URI.
ids.push(keyName);
}
return ids;
};
/**
* Set the key with keyName as the default key for the identity with name
* identityName.
* @param {Name} identityName The name of the identity. This copies the name.
* @param {Name} keyName The name of the key. This copies the name.
* @return {SyncPromise} A promise which fulfills when the default key is set,
* or a promise rejected with Pib.Error if the key does not exist.
*/
PibMemory.prototype.setDefaultKeyOfIdentityPromise = function
(identityName, keyName)
{
if (!this.hasKey_(keyName))
return SyncPromise.reject(new Pib.Error(new Error
("Key `" + keyName.toUri() + "` not found")));
// Copy the Name.
this.defaultKeyNames_[identityName.toUri()] = new Name(keyName);
return SyncPromise.resolve();
};
/**
* Get the name of the default key for the identity with name identityName.
* @param {Name} identityName The name of the identity.
* @return {SyncPromise} A promise which returns the name of the default key as
* a fresh copy, or a promise rejected with Pib.Error if the identity does not
* exist.
*/
PibMemory.prototype.getDefaultKeyOfIdentityPromise = function(identityName)
{
var defaultKey = this.defaultKeyNames_[identityName.toUri()];
if (defaultKey == undefined)
return SyncPromise.reject(new Pib.Error(new Error
("No default key for identity `" + identityName.toUri() + "`")));
// Copy the name.
return SyncPromise.resolve(new Name(defaultKey));
};
// Certificate management.
/**
* Check for the existence of a certificate with name certificateName.
* @param {Name} certificateName The name of the certificate.
* @return {SyncPromise} A promise which returns true if the certificate exists,
* otherwise false.
*/
PibMemory.prototype.hasCertificatePromise = function(certificateName)
{
return SyncPromise.resolve(this.hasCertificate_(certificateName));
};
/**
* Do the work of hasCertificatePromise.
*/
PibMemory.prototype.hasCertificate_ = function(certificateName)
{
return certificateName.toUri() in this.certificates_;
};
/**
* Add the certificate. If a certificate with the same name (without implicit
* digest) already exists, then overwrite the certificate. If the key or
* identity does not exist, they will be created. If no default certificate for
* the key has been set, then set the added certificate as the default for the
* key. If no default key was set for the identity, it will be set as the
* default key for the identity. If no default identity was selected, the
* certificate's identity becomes the default.
* @param {CertificateV2} certificate The certificate to add. This copies the
* object.
* @return {SyncPromise} A promise which fulfills when the certificate is added.
*/
PibMemory.prototype.addCertificatePromise = function(certificate)
{
var certificateNameCopy = new Name(certificate.getName());
// getKeyName already makes a new Name.
var keyNameCopy = certificate.getKeyName();
var identity = certificate.getIdentity();
this.addKey_(identity, keyNameCopy, certificate.getContent().buf());
this.certificates_[certificateNameCopy.toUri()] =
new CertificateV2(certificate);
var keyNameUri = keyNameCopy.toUri();
if (!(keyNameUri in this.defaultCertificateNames_))
this.defaultCertificateNames_[keyNameUri] = certificateNameCopy;
return SyncPromise.resolve();
};
/**
* Remove the certificate with name certificateName. If the certificate does not
* exist, do nothing.
* @param {Name} certificateName The name of the certificate.
* @return {SyncPromise} A promise which fulfills when the certificate is
* removed.
*/
PibMemory.prototype.removeCertificatePromise = function(certificateName)
{
this.removeCertificate_(certificateName);
return SyncPromise.resolve();
};
/**
* Do the work of removeCertificatePromise.
*/
PibMemory.prototype.removeCertificate_ = function(certificateName)
{
delete this.certificates_[certificateName.toUri()];
var keyName = CertificateV2.extractKeyNameFromCertName(certificateName);
var keyNameUri = keyName.toUri();
var defaultCertificateName = this.defaultCertificateNames_[keyNameUri];
if (defaultCertificateName != undefined &&
defaultCertificateName.equals(certificateName))
delete this.defaultCertificateNames_[keyNameUri];
};
/**
* Get the certificate with name certificateName.
* @param {Name} certificateName The name of the certificate.
* @return {SyncPromise} A promise which returns the CertificateV2, or a promise
* rejected with Pib.Error if the certificate does not exist.
*/
PibMemory.prototype.getCertificatePromise = function(certificateName)
{
if (!this.hasCertificate_(certificateName))
return SyncPromise.reject(new Pib.Error(new Error
("Certificate `" + certificateName.toUri() + "` does not exist")));
return SyncPromise.resolve(new CertificateV2
(this.certificates_[certificateName.toUri()]));
};
/**
* Get a list of certificate names of the key with id keyName. The returned
* certificate names can be used to create a PibCertificateContainer. With a
* certificate name and a backend implementation, one can obtain the certificate.
* @param {Name} keyName The name of the key.
* @return {SyncPromise} A promise which returns the set of certificate names as
* an array of Name. The Name objects are fresh copies. If the key does not
* exist, return an empty array.
*/
PibMemory.prototype.getCertificatesOfKeyPromise = function(keyName)
{
return SyncPromise.resolve(this.getCertificatesOfKey_(keyName));
};
/**
* Do the work of getCertificatesOfKeyPromise.
*/
PibMemory.prototype.getCertificatesOfKey_ = function(keyName)
{
var certificateNames = [];
for (var certificateNameUri in this.certificates_) {
if (CertificateV2.extractKeyNameFromCertName
(this.certificates_[certificateNameUri].getName()).equals(keyName))
certificateNames.push(new Name(certificateNameUri));
}
return certificateNames;
};
/**
* Set the cert with name certificateName as the default for the key with
* keyName.
* @param {Name} keyName The name of the key.
* @param {Name} certificateName The name of the certificate. This copies the
* name.
* @return {SyncPromise} A promise which fulfills when the default certificate
* is set, or a promise rejected with Pib.Error if the certificate with name
* certificateName does not exist.
*/
PibMemory.prototype.setDefaultCertificateOfKeyPromise = function
(keyName, certificateName)
{
if (!this.hasCertificate_(certificateName))
return SyncPromise.reject(new Pib.Error(new Error
("Certificate `" + certificateName.toUri() + "` does not exist")));
// Copy the Name.
this.defaultCertificateNames_[keyName.toUri()] = new Name(certificateName);
return SyncPromise.resolve();
};
/**
* Get the default certificate for the key with eyName.
* @param {Name} keyName The name of the key.
* @return {SyncPromise} A promise which returns a copy of the default
* CertificateV2, or a promise rejected with Pib.Error if the default
* certificate does not exist.
*/
PibMemory.prototype.getDefaultCertificateOfKeyPromise = function(keyName)
{
var certificateName = this.defaultCertificateNames_[keyName.toUri()];
if (certificateName == undefined)
return SyncPromise.reject(new Pib.Error(new Error
("No default certificate for key `" + keyName.toUri() + "`")));
var certificate = this.certificates_[certificateName.toUri()];
return SyncPromise.resolve(new CertificateV2(certificate));
};