Source: security/identity/private-key-storage.js

  1. /**
  2. * Copyright (C) 2014-2018 Regents of the University of California.
  3. * @author: Jeff Thompson <jefft0@remap.ucla.edu>
  4. * From ndn-cxx security by Yingdi Yu <yingdi@cs.ucla.edu>.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. * A copy of the GNU Lesser General Public License is in the file COPYING.
  19. */
  20. /** @ignore */
  21. var SyncPromise = require('../../util/sync-promise.js').SyncPromise; /** @ignore */
  22. var DerNode = require('../../encoding/der/der-node.js').DerNode;
  23. /**
  24. * PrivateKeyStorage is an abstract class which declares methods for working
  25. * with a private key storage. You should use a subclass.
  26. * @constructor
  27. */
  28. var PrivateKeyStorage = function PrivateKeyStorage()
  29. {
  30. };
  31. exports.PrivateKeyStorage = PrivateKeyStorage;
  32. /**
  33. * Generate a pair of asymmetric keys.
  34. * @param {Name} keyName The name of the key pair.
  35. * @param {KeyParams} params The parameters of the key.
  36. * @param {boolean} (optional) useSync If true then return a SyncPromise which
  37. * is already fulfilled. If omitted or false, this may return a SyncPromise or
  38. * an async Promise.
  39. * @return {Promise|SyncPromise} A promise that fulfills when the pair is
  40. * generated.
  41. */
  42. PrivateKeyStorage.prototype.generateKeyPairPromise = function
  43. (keyName, params, useSync)
  44. {
  45. return SyncPromise.reject(new Error
  46. ("PrivateKeyStorage.generateKeyPairPromise is not implemented"));
  47. };
  48. /**
  49. * Generate a pair of asymmetric keys.
  50. * @param {Name} keyName The name of the key pair.
  51. * @param {KeyParams} params The parameters of the key.
  52. * @throws Error If generateKeyPairPromise doesn't return a SyncPromise which
  53. * is already fulfilled.
  54. */
  55. PrivateKeyStorage.prototype.generateKeyPair = function(keyName, params)
  56. {
  57. SyncPromise.getValue(this.generateKeyPairPromise(keyName, params, true));
  58. };
  59. /**
  60. * Delete a pair of asymmetric keys. If the key doesn't exist, do nothing.
  61. * @param {Name} keyName The name of the key pair.
  62. * @param {boolean} useSync (optional) If true then return a SyncPromise which
  63. * is already fulfilled. If omitted or false, this may return a SyncPromise or
  64. * an async Promise.
  65. * @return {Promise|SyncPromise} A promise that fulfills when the key pair is
  66. * deleted.
  67. */
  68. PrivateKeyStorage.prototype.deleteKeyPairPromise = function(keyName, useSync)
  69. {
  70. return SyncPromise.reject(new Error
  71. ("PrivateKeyStorage.deleteKeyPairPromise is not implemented"));
  72. };
  73. /**
  74. * Delete a pair of asymmetric keys. If the key doesn't exist, do nothing.
  75. * @param {Name} keyName The name of the key pair.
  76. * @throws Error If deleteKeyPairPromise doesn't return a SyncPromise which
  77. * is already fulfilled.
  78. */
  79. PrivateKeyStorage.prototype.deleteKeyPair = function(keyName)
  80. {
  81. SyncPromise.getValue(this.deleteKeyPairPromise(keyName, true));
  82. };
  83. /**
  84. * Get the public key
  85. * @param {Name} keyName The name of public key.
  86. * @param {boolean} useSync (optional) If true then return a SyncPromise which
  87. * is already fulfilled. If omitted or false, this may return a SyncPromise or
  88. * an async Promise.
  89. * @return {Promise|SyncPromise} A promise that returns the PublicKey.
  90. */
  91. PrivateKeyStorage.prototype.getPublicKeyPromise = function(keyName, useSync)
  92. {
  93. return SyncPromise.reject(new Error
  94. ("PrivateKeyStorage.getPublicKeyPromise is not implemented"));
  95. };
  96. /**
  97. * Get the public key
  98. * @param {Name} keyName The name of public key.
  99. * @return {PublicKey} The public key.
  100. * @throws Error If getPublicKeyPromise doesn't return a SyncPromise which
  101. * is already fulfilled.
  102. */
  103. PrivateKeyStorage.prototype.getPublicKey = function(keyName)
  104. {
  105. return SyncPromise.getValue(this.getPublicKeyPromise(keyName, true));
  106. };
  107. /**
  108. * Fetch the private key for keyName and sign the data to produce a signature Blob.
  109. * @param {Buffer} data Pointer to the input byte array.
  110. * @param {Name} keyName The name of the signing key.
  111. * @param {number} digestAlgorithm (optional) The digest algorithm from
  112. * DigestAlgorithm, such as DigestAlgorithm.SHA256. If omitted, use
  113. * DigestAlgorithm.SHA256.
  114. * @param {boolean} useSync (optional) If true then return a SyncPromise which
  115. * is already fulfilled. If omitted or false, this may return a SyncPromise or
  116. * an async Promise.
  117. * @return {Promise|SyncPromise} A promise that returns the signature Blob.
  118. */
  119. PrivateKeyStorage.prototype.signPromise = function
  120. (data, keyName, digestAlgorithm, useSync)
  121. {
  122. return SyncPromise.reject(new Error("PrivateKeyStorage.sign is not implemented"));
  123. };
  124. /**
  125. * Fetch the private key for keyName and sign the data to produce a signature Blob.
  126. * @param {Buffer} data Pointer to the input byte array.
  127. * @param {Name} keyName The name of the signing key.
  128. * @param {number} digestAlgorithm (optional) The digest algorithm from
  129. * DigestAlgorithm, such as DigestAlgorithm.SHA256. If omitted, use
  130. * DigestAlgorithm.SHA256.
  131. * @return {Blob} The signature Blob.
  132. * @throws Error If signPromise doesn't return a SyncPromise which is already
  133. * fulfilled.
  134. */
  135. PrivateKeyStorage.prototype.sign = function(data, keyName, digestAlgorithm)
  136. {
  137. return SyncPromise.getValue
  138. (this.signPromise(data, keyName, digestAlgorithm, true));
  139. };
  140. /**
  141. * Decrypt data.
  142. * @param {Name} keyName The name of the decrypting key.
  143. * @param {Buffer} data The byte to be decrypted.
  144. * @param {boolean} isSymmetric (optional) If true symmetric encryption is used,
  145. * otherwise asymmetric encryption is used. If omitted, use asymmetric
  146. * encryption.
  147. * @return {Blob} The decrypted data.
  148. */
  149. PrivateKeyStorage.prototype.decrypt = function(keyName, data, isSymmetric)
  150. {
  151. throw new Error("PrivateKeyStorage.decrypt is not implemented");
  152. };
  153. /**
  154. * Encrypt data.
  155. * @param {Name} keyName The name of the encrypting key.
  156. * @param {Buffer} data The byte to be encrypted.
  157. * @param {boolean} isSymmetric (optional) If true symmetric encryption is used,
  158. * otherwise asymmetric encryption is used. If omitted, use asymmetric
  159. * encryption.
  160. * @return {Blob} The encrypted data.
  161. */
  162. PrivateKeyStorage.prototype.encrypt = function(keyName, data, isSymmetric)
  163. {
  164. throw new Error("PrivateKeyStorage.encrypt is not implemented");
  165. };
  166. /**
  167. * Generate a symmetric key.
  168. * @param {Name} keyName The name of the key.
  169. * @param {KeyParams} params The parameters of the key.
  170. */
  171. PrivateKeyStorage.prototype.generateKey = function(keyName, params)
  172. {
  173. throw new Error("PrivateKeyStorage.generateKey is not implemented");
  174. };
  175. /**
  176. * Check if a particular key exists.
  177. * @param {Name} keyName The name of the key.
  178. * @param {number} keyClass The class of the key, e.g. KeyClass.PUBLIC,
  179. * KeyClass.PRIVATE, or KeyClass.SYMMETRIC.
  180. * @param {boolean} useSync (optional) If true then return a SyncPromise which
  181. * is already fulfilled. If omitted or false, this may return a SyncPromise or
  182. * an async Promise.
  183. * @return {Promise|SyncPromise} A promise which returns true if the key exists.
  184. */
  185. PrivateKeyStorage.prototype.doesKeyExistPromise = function
  186. (keyName, keyClass, useSync)
  187. {
  188. return SyncPromise.reject(new Error
  189. ("PrivateKeyStorage.doesKeyExist is not implemented"));
  190. };
  191. /**
  192. * Check if a particular key exists.
  193. * @param {Name} keyName The name of the key.
  194. * @param {number} keyClass The class of the key, e.g. KeyClass.PUBLIC,
  195. * KeyClass.PRIVATE, or KeyClass.SYMMETRIC.
  196. * @return {boolean} True if the key exists.
  197. * @throws Error If doesKeyExistPromise doesn't return a SyncPromise which
  198. * is already fulfilled.
  199. */
  200. PrivateKeyStorage.prototype.doesKeyExist = function(keyName, keyClass)
  201. {
  202. return SyncPromise.getValue(this.doesKeyExistPromise(keyName, keyClass, true));
  203. };
  204. /**
  205. * Encode the private key to a PKCS #8 private key. We do this explicitly here
  206. * to avoid linking to extra OpenSSL libraries.
  207. * @param {Buffer} privateKeyDer The input private key DER.
  208. * @param {OID} oid The OID of the privateKey.
  209. * @param {DerNode} parameters The DerNode of the parameters for the OID.
  210. * @return {Blob} The PKCS #8 private key DER.
  211. */
  212. PrivateKeyStorage.encodePkcs8PrivateKey = function
  213. (privateKeyDer, oid, parameters)
  214. {
  215. var algorithmIdentifier = new DerNode.DerSequence();
  216. algorithmIdentifier.addChild(new DerNode.DerOid(oid));
  217. algorithmIdentifier.addChild(parameters);
  218. var result = new DerNode.DerSequence();
  219. result.addChild(new DerNode.DerInteger(0));
  220. result.addChild(algorithmIdentifier);
  221. result.addChild(new DerNode.DerOctetString(privateKeyDer));
  222. return result.encode();
  223. };
  224. /**
  225. * Encode the RSAKey private key as a PKCS #1 private key.
  226. * @param {RSAKey} rsaKey The RSAKey private key.
  227. * @return {Blob} The PKCS #1 private key DER.
  228. */
  229. PrivateKeyStorage.encodePkcs1PrivateKeyFromRSAKey = function(rsaKey)
  230. {
  231. // Imitate KJUR getEncryptedPKCS5PEMFromRSAKey.
  232. var result = new DerNode.DerSequence();
  233. result.addChild(new DerNode.DerInteger(0));
  234. result.addChild(new DerNode.DerInteger(PrivateKeyStorage.bigIntegerToBuffer(rsaKey.n)));
  235. result.addChild(new DerNode.DerInteger(rsaKey.e));
  236. result.addChild(new DerNode.DerInteger(PrivateKeyStorage.bigIntegerToBuffer(rsaKey.d)));
  237. result.addChild(new DerNode.DerInteger(PrivateKeyStorage.bigIntegerToBuffer(rsaKey.p)));
  238. result.addChild(new DerNode.DerInteger(PrivateKeyStorage.bigIntegerToBuffer(rsaKey.q)));
  239. result.addChild(new DerNode.DerInteger(PrivateKeyStorage.bigIntegerToBuffer(rsaKey.dmp1)));
  240. result.addChild(new DerNode.DerInteger(PrivateKeyStorage.bigIntegerToBuffer(rsaKey.dmq1)));
  241. result.addChild(new DerNode.DerInteger(PrivateKeyStorage.bigIntegerToBuffer(rsaKey.coeff)));
  242. return result.encode();
  243. };
  244. /**
  245. * Encode the public key values in the RSAKey private key as a
  246. * SubjectPublicKeyInfo.
  247. * @param {RSAKey} rsaKey The RSAKey private key with the public key values.
  248. * @return {Blob} The SubjectPublicKeyInfo DER.
  249. */
  250. PrivateKeyStorage.encodePublicKeyFromRSAKey = function(rsaKey)
  251. {
  252. var rsaPublicKey = new DerNode.DerSequence();
  253. rsaPublicKey.addChild(new DerNode.DerInteger(PrivateKeyStorage.bigIntegerToBuffer(rsaKey.n)));
  254. rsaPublicKey.addChild(new DerNode.DerInteger(rsaKey.e));
  255. var algorithmIdentifier = new DerNode.DerSequence();
  256. algorithmIdentifier.addChild
  257. (new DerNode.DerOid(new OID(PrivateKeyStorage.RSA_ENCRYPTION_OID)));
  258. algorithmIdentifier.addChild(new DerNode.DerNull());
  259. var result = new DerNode.DerSequence();
  260. result.addChild(algorithmIdentifier);
  261. result.addChild(new DerNode.DerBitString(rsaPublicKey.encode().buf(), 0));
  262. return result.encode();
  263. };
  264. /**
  265. * Convert a BigInteger to a Buffer.
  266. * @param {BigInteger} bigInteger The BigInteger.
  267. * @return {Buffer} The Buffer.
  268. */
  269. PrivateKeyStorage.bigIntegerToBuffer = function(bigInteger)
  270. {
  271. // Imitate KJUR.asn1.ASN1Util.bigIntToMinTwosComplementsHex.
  272. var hex = bigInteger.toString(16);
  273. if (hex.substr(0, 1) == "-")
  274. throw new Error
  275. ("PrivateKeyStorage.bigIntegerToBuffer: Negative integers are not currently supported");
  276. if (hex.length % 2 == 1)
  277. // Odd number of characters.
  278. hex = "0" + hex;
  279. else {
  280. if (! hex.match(/^[0-7]/))
  281. // The first byte is >= 0x80, so prepend a zero to keep it positive.
  282. hex = "00" + hex;
  283. }
  284. return new Buffer(hex, 'hex');
  285. };
  286. PrivateKeyStorage.RSA_ENCRYPTION_OID = "1.2.840.113549.1.1.1";
  287. PrivateKeyStorage.EC_ENCRYPTION_OID = "1.2.840.10045.2.1";