1'use strict'; 2 3const common = require('../common'); 4 5if (!common.hasCrypto) 6 common.skip('missing crypto'); 7 8const assert = require('assert'); 9const { webcrypto } = require('crypto'); 10const { subtle } = webcrypto; 11 12const kTests = [ 13 { 14 name: 'X25519', 15 size: 32, 16 pkcs8: '302e020100300506032b656e04220420c8838e76d057dfb7d8c95a69e138160ad' + 17 'd6373fd71a4d276bb56e3a81b64ff61', 18 spki: '302a300506032b656e0321001cf2b1e6022ec537371ed7f53e54fa1154d83e98eb' + 19 '64ea51fae5b3307cfe9706', 20 result: '2768409dfab99ec23b8c89b93ff5880295f76176088f89e43dfebe7ea1950008' 21 }, 22 { 23 name: 'X448', 24 size: 56, 25 pkcs8: '3046020100300506032b656f043a043858c7d29a3eb519b29d00cfb191bb64fc6' + 26 'd8a42d8f17176272b89f2272d1819295c6525c0829671b052ef0727530f188e31' + 27 'd0cc53bf26929e', 28 spki: '3042300506032b656f033900b604a1d1a5cd1d9426d561ef630a9eb16cbe69d5b9' + 29 'ca615edc53633efb52ea31e6e6a0a1dbacc6e76cbce6482d7e4ba3d55d9e802765' + 30 'ce6f', 31 result: 'f0f6c5f17f94f4291eab7178866d37ec8906dd6c514143dc85be7cf28deff39b' 32 }, 33]; 34 35async function prepareKeys() { 36 const keys = {}; 37 await Promise.all( 38 kTests.map(async ({ name, size, pkcs8, spki, result }) => { 39 const [ 40 privateKey, 41 publicKey, 42 ] = await Promise.all([ 43 subtle.importKey( 44 'pkcs8', 45 Buffer.from(pkcs8, 'hex'), 46 { name }, 47 true, 48 ['deriveKey', 'deriveBits']), 49 subtle.importKey( 50 'spki', 51 Buffer.from(spki, 'hex'), 52 { name }, 53 true, 54 []), 55 ]); 56 keys[name] = { 57 privateKey, 58 publicKey, 59 size, 60 result, 61 }; 62 })); 63 return keys; 64} 65 66(async function() { 67 const keys = await prepareKeys(); 68 const otherArgs = [ 69 { name: 'HMAC', hash: 'SHA-256', length: 256 }, 70 true, 71 ['sign', 'verify']]; 72 73 await Promise.all( 74 Object.keys(keys).map(async (name) => { 75 const { result, privateKey, publicKey } = keys[name]; 76 77 { 78 // Good parameters 79 const key = await subtle.deriveKey({ 80 name, 81 public: publicKey 82 }, privateKey, ...otherArgs); 83 84 const raw = await subtle.exportKey('raw', key); 85 86 assert.strictEqual(Buffer.from(raw).toString('hex'), result); 87 } 88 89 { 90 // Case insensitivity 91 const key = await subtle.deriveKey({ 92 name: name.toLowerCase(), 93 public: publicKey 94 }, privateKey, { 95 name: 'HmAc', 96 hash: 'SHA-256', 97 length: 256 98 }, true, ['sign', 'verify']); 99 100 const raw = await subtle.exportKey('raw', key); 101 102 assert.strictEqual(Buffer.from(raw).toString('hex'), result); 103 } 104 })); 105 106 // Error tests 107 { 108 // Missing public property 109 await assert.rejects( 110 subtle.deriveKey( 111 { name: 'X448' }, 112 keys.X448.privateKey, 113 ...otherArgs), 114 { code: 'ERR_MISSING_OPTION' }); 115 } 116 117 { 118 // The public property is not a CryptoKey 119 await assert.rejects( 120 subtle.deriveKey( 121 { 122 name: 'X448', 123 public: { message: 'Not a CryptoKey' } 124 }, 125 keys.X448.privateKey, 126 ...otherArgs), 127 { code: 'ERR_INVALID_ARG_TYPE' }); 128 } 129 130 { 131 // Mismatched named curves 132 await assert.rejects( 133 subtle.deriveKey( 134 { 135 name: 'X448', 136 public: keys.X25519.publicKey 137 }, 138 keys.X448.privateKey, 139 ...otherArgs), 140 { message: 'The public and private keys must be of the same type' }); 141 } 142 143 { 144 // Base key is not a private key 145 await assert.rejects( 146 subtle.deriveKey( 147 { 148 name: 'X448', 149 public: keys.X448.publicKey 150 }, 151 keys.X448.publicKey, 152 ...otherArgs), 153 { name: 'InvalidAccessError' }); 154 } 155 156 { 157 // Public is not a public key 158 await assert.rejects( 159 subtle.deriveKey( 160 { 161 name: 'X448', 162 public: keys.X448.privateKey 163 }, 164 keys.X448.privateKey, 165 ...otherArgs), 166 { name: 'InvalidAccessError' }); 167 } 168 169 { 170 // Public is a secret key 171 const keyData = webcrypto.getRandomValues(new Uint8Array(32)); 172 const key = await subtle.importKey( 173 'raw', 174 keyData, 175 { name: 'AES-CBC', length: 256 }, 176 false, ['encrypt']); 177 178 await assert.rejects( 179 subtle.deriveKey( 180 { 181 name: 'X448', 182 public: key 183 }, 184 keys.X448.publicKey, 185 ...otherArgs), 186 { name: 'InvalidAccessError' }); 187 } 188})().then(common.mustCall()); 189