/**
* 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/key.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 CertificateV2 = require('../v2/certificate-v2.js').CertificateV2; /** @ignore */
var SyncPromise = require('../../util/sync-promise.js').SyncPromise;
/**
* A PibKey provides access to a key at the second level in the PIB's
* Identity-Key-Certificate hierarchy. A PibKey object has a Name (identity +
* "KEY" + keyId), and contains one or more CertificateV2 objects, one of which
* is set as the default certificate of this key. A certificate can be directly
* accessed by getting a CertificateV2 object.
*
* Create a PibKey which uses the impl backend implementation. This constructor
* should only be called by PibKeyContainer.
*
* @param {PibKeyImpl} impl An object of a subclass of PibKeyImpl.
* @constructor
*/
var PibKey = function PibKey(impl)
{
this.impl_ = impl;
};
exports.PibKey = PibKey;
/**
* Get the key name.
* @return {Name} The key name. You must not modify the Name object. If you need
* to modify it, make a copy.
* @throws Error if the backend implementation instance is invalid.
*/
PibKey.prototype.getName = function() { return this.lock_().getName(); };
/**
* Get the name of the identity this key belongs to.
* @return {Name} The name of the identity. You must not modify the Key object.
* If you need to modify it, make a copy.
* @throws Error if the backend implementation instance is invalid.
*/
PibKey.prototype.getIdentityName = function()
{
return this.lock_().getIdentityName();
};
/**
* Get the key type.
* @return {number} The key type as an int from the KeyType enum.
* @throws Error if the backend implementation instance is invalid.
*/
PibKey.prototype.getKeyType = function() { return this.lock_().getKeyType(); };
/**
* Get the public key encoding.
* @return {Blob} The public key encoding.
* @throws Error if the backend implementation instance is invalid.
*/
PibKey.prototype.getPublicKey = function() { return this.lock_().getPublicKey(); };
/**
* Get the certificate with name certificateName.
* @param {Name} certificateName The name of the certificate.
* @param {boolean} useSync (optional) If true then return a SyncPromise which
* is already fulfilled. If omitted or false, this may return a SyncPromise or
* an async Promise.
* @return {Promise|SyncPromise} A promise which returns a copy of the
* CertificateV2, or a promise rejected with Error if certificateName does not
* match the key name (or if the backend implementation instance is invalid), or
* a promise rejected with Pib.Error if the certificate does not exist.
*/
PibKey.prototype.getCertificatePromise = function(certificateName, useSync)
{
try {
return this.lock_().getCertificatePromise(certificateName, useSync);
} catch (ex) {
return SyncPromise.reject(ex);
}
};
/**
* Get the certificate with name certificateName.
* @param {Name} certificateName The name of the certificate.
* @param {function} onComplete (optional) This calls
* onComplete(certificate) with a copy of the CertificateV2. If omitted, the
* return value is described below. (Some database libraries only use a callback,
* so onComplete is required to use these.)
* 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 {function} onError (optional) If defined, then onComplete must be
* defined and if there is an exception, then this calls onError(exception)
* with the exception. If onComplete is defined but onError is undefined, then
* this will log any thrown exception. (Some database libraries only use a
* callback, so onError is required to be notified of an exception.)
* 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.
* @return {CertificateV2} If onComplete is omitted, return a copy of the
* CertificateV2. Otherwise, if onComplete is supplied then return undefined and
* use onComplete as described above.
* @throws Error if certificateName does not match the key name (or if the
* backend implementation instance is invalid), or Pib.Error if the certificate
* does not exist. However, if onComplete and onError are defined, then if there
* is an exception return undefined and call onError(exception).
*/
PibKey.prototype.getCertificate = function(certificateName, onComplete, onError)
{
return SyncPromise.complete(onComplete, onError,
this.getCertificatePromise(certificateName, !onComplete));
};
/**
* Get the default certificate for this Key.
* @param {boolean} useSync (optional) If true then return a SyncPromise which
* is already fulfilled. If omitted or false, this may return a SyncPromise or
* an async Promise.
* @return {Promise|SyncPromise} A promise which returns the default
* CertificateV2, or a promise rejected with Error if the backend implementation
* instance is invalid, or a promise rejected with Pib.Error if the default
* certificate does not exist.
*/
PibKey.prototype.getDefaultCertificatePromise = function(useSync)
{
try {
return this.lock_().getDefaultCertificatePromise(useSync);
} catch (ex) {
return SyncPromise.reject(ex);
}
};
/**
* Get the default certificate for this Key.
* @param {function} onComplete (optional) This calls
* onComplete(certificate) with the default CertificateV2. If omitted, the
* return value is described below. (Some database libraries only use a callback,
* so onComplete is required to use these.)
* 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 {function} onError (optional) If defined, then onComplete must be
* defined and if there is an exception, then this calls onError(exception)
* with the exception. If onComplete is defined but onError is undefined, then
* this will log any thrown exception. (Some database libraries only use a
* callback, so onError is required to be notified of an exception.)
* 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.
* @return {CertificateV2} If onComplete is omitted, return the default
* CertificateV2. Otherwise, if onComplete is supplied then return undefined and
* use onComplete as described above.
* @throws Error if the backend implementation instance is invalid, Pib.Error if
* the default certificate does not exist. However, if onComplete and onError
* are defined, then if there is an exception return undefined and call
* onError(exception).
*/
PibKey.prototype.getDefaultCertificate = function(onComplete, onError)
{
return SyncPromise.complete(onComplete, onError,
this.getDefaultCertificatePromise(!onComplete));
};
/**
* Construct a key name based on the appropriate naming conventions.
* @param {Name} identityName The name of the identity.
* @param {Name.Component} keyId The key ID name component.
* @return {Name} The constructed name as a new Name.
*/
PibKey.constructKeyName = function(identityName, keyId)
{
var keyName = new Name(identityName);
keyName.append(CertificateV2.KEY_COMPONENT).append(keyId);
return keyName;
};
/**
* Check if keyName follows the naming conventions for a key name.
* @param {Name} keyName The name of the key.
* @return {boolean} True if keyName follows the naming conventions, otherwise
* false.
*/
PibKey.isValidKeyName = function(keyName)
{
return keyName.size() > CertificateV2.MIN_KEY_NAME_LENGTH &&
keyName.get(-CertificateV2.MIN_KEY_NAME_LENGTH).equals
(CertificateV2.KEY_COMPONENT);
};
/**
* Extract the identity namespace from keyName.
* @param {Name} keyName The name of the key.
* @return {Name} The identity name as a new Name.
*/
PibKey.extractIdentityFromKeyName = function(keyName)
{
if (!PibKey.isValidKeyName(keyName))
throw new Error("Key name `" + keyName.toUri() +
"` does not follow the naming conventions");
// Trim everything after and including "KEY".
return keyName.getPrefix(-CertificateV2.MIN_KEY_NAME_LENGTH);
};
/**
* Add the certificate. If a certificate with the same name (without implicit
* digest) already exists, then overwrite the certificate. If no default
* certificate for the key has been set, then set the added certificate as
* default for the key. This should only be called by KeyChain.
* @param {CertificateV2} certificate The certificate to add. This copies the
* object.
* @param {boolean} useSync (optional) If true then return a SyncPromise which
* is already fulfilled. If omitted or false, this may return a SyncPromise or
* an async Promise.
* @return {Promise|SyncPromise} A promise which fulfills when finished, or a
* promise rejected with Error if the name of the certificate does not match the
* key name.
*/
PibKey.prototype.addCertificatePromise_ = function(certificate, useSync)
{
return this.lock_().addCertificatePromise(certificate, useSync);
};
/**
* Remove the certificate with name certificateName. If the certificate does not
* exist, do nothing. This should only be called by KeyChain.
* @param {Name} certificateName The name of the certificate.
* @param {boolean} useSync (optional) If true then return a SyncPromise which
* is already fulfilled. If omitted or false, this may return a SyncPromise or
* an async Promise.
* @return {Promise|SyncPromise} A promise which fulfills when finished, or a
* promise rejected with Error if certificateName does not match the key name.
*/
PibKey.prototype.removeCertificatePromise_ = function(certificateName, useSync)
{
return this.lock_().removeCertificatePromise(certificateName, useSync);
};
/**
* Set the existing certificate with name certificateName as the default
* certificate. This should only be called by KeyChain.
* @param {Name} certificateName The name of the certificate.
* @param {boolean} useSync (optional) If true then return a SyncPromise which
* is already fulfilled. If omitted or false, this may return a SyncPromise or
* an async Promise.
* @return {Promise|SyncPromise} A promise which returns the default
* CertificateV2, or a promise rejected with Error if certificateName does not
* match the key name, or a promise rejected with Pib.Error if
* certificateOrCertificateName is the certificate Name and the certificate does
* not exist.
*/
PibKey.prototype.setDefaultCertificatePromise_ = function(certificateName, useSync)
{
return this.lock_().setDefaultCertificatePromise(certificateName, useSync);
};
/**
* Get the PibCertificateContainer in the PibKeyImpl. This should only be called
* by KeyChain.
* @return {PibCertificateContainer} The PibCertificateContainer.
*/
PibKey.prototype.getCertificates_ = function()
{
return this.lock_().certificates_;
};
/**
* Check the validity of the impl_ instance.
* @return {PibKeyImpl} The PibKeyImpl when the instance is valid.
* @throws Error if the backend implementation instance is invalid.
*/
PibKey.prototype.lock_ = function()
{
if (this.impl_ == null)
throw new Error("Invalid key instance");
return this.impl_;
};