getPublicKey.tentative.https.any.js (8857B)
1 // META: title=WebCryptoAPI: getPublicKey() method 2 // META: timeout=long 3 // META: script=util/helpers.js 4 5 "use strict"; 6 7 const algorithms = [ 8 { 9 name: "ECDH", 10 generateKeyParams: { name: "ECDH", namedCurve: "P-256" }, 11 usages: ["deriveKey", "deriveBits"], 12 publicKeyUsages: [] 13 }, 14 { 15 name: "ECDSA", 16 generateKeyParams: { name: "ECDSA", namedCurve: "P-256" }, 17 usages: ["sign", "verify"], 18 publicKeyUsages: ["verify"] 19 }, 20 { 21 name: "Ed25519", 22 generateKeyParams: { name: "Ed25519" }, 23 usages: ["sign", "verify"], 24 publicKeyUsages: ["verify"] 25 }, 26 { 27 name: "RSA-OAEP", 28 generateKeyParams: { 29 name: "RSA-OAEP", 30 modulusLength: 2048, 31 publicExponent: new Uint8Array([1, 0, 1]), 32 hash: "SHA-256" 33 }, 34 usages: ["encrypt", "decrypt"], 35 publicKeyUsages: ["encrypt"] 36 }, 37 { 38 name: "RSA-PSS", 39 generateKeyParams: { 40 name: "RSA-PSS", 41 modulusLength: 2048, 42 publicExponent: new Uint8Array([1, 0, 1]), 43 hash: "SHA-256" 44 }, 45 usages: ["sign", "verify"], 46 publicKeyUsages: ["verify"] 47 }, 48 { 49 name: "RSASSA-PKCS1-v1_5", 50 generateKeyParams: { 51 name: "RSASSA-PKCS1-v1_5", 52 modulusLength: 2048, 53 publicExponent: new Uint8Array([1, 0, 1]), 54 hash: "SHA-256" 55 }, 56 usages: ["sign", "verify"], 57 publicKeyUsages: ["verify"] 58 }, 59 { 60 name: "X25519", 61 generateKeyParams: { name: "X25519" }, 62 usages: ["deriveKey", "deriveBits"], 63 publicKeyUsages: [] 64 } 65 ]; 66 67 // Test basic functionality for supported algorithms 68 algorithms.forEach(function(algorithm) { 69 promise_test(async function(t) { 70 // Generate a key pair 71 const keyPair = await crypto.subtle.generateKey( 72 algorithm.generateKeyParams, 73 false, // extractable 74 algorithm.usages 75 ); 76 77 assert_true(keyPair.privateKey instanceof CryptoKey, "Generated private key"); 78 assert_equals(keyPair.privateKey.type, "private", "Private key type"); 79 80 // Test getPublicKey with valid usages 81 const publicKey = await crypto.subtle.getPublicKey( 82 keyPair.privateKey, 83 algorithm.publicKeyUsages 84 ); 85 86 // Verify the returned public key 87 assert_true(publicKey instanceof CryptoKey, "getPublicKey returns a CryptoKey"); 88 assert_equals(publicKey.type, "public", "Returned key is public"); 89 assert_equals(publicKey.algorithm.name, algorithm.name, "Algorithm name matches"); 90 assert_true(publicKey.extractable, "Public key is extractable"); 91 92 // Verify usages 93 assert_equals(publicKey.usages.length, algorithm.publicKeyUsages.length, "Usage count matches"); 94 algorithm.publicKeyUsages.forEach(function(usage) { 95 assert_true(publicKey.usages.includes(usage), `Has ${usage} usage`); 96 }); 97 98 // Verify that the derived public key matches the original public key 99 // by comparing their exported forms 100 const originalExported = await crypto.subtle.exportKey("spki", keyPair.publicKey); 101 const derivedExported = await crypto.subtle.exportKey("spki", publicKey); 102 103 assert_array_equals( 104 new Uint8Array(originalExported), 105 new Uint8Array(derivedExported), 106 "Exported public keys match" 107 ); 108 109 }, `getPublicKey works for ${algorithm.name}`); 110 }); 111 112 // Test functional equivalence - ensure derived public key works for crypto operations 113 promise_test(async function(t) { 114 const keyPair = await crypto.subtle.generateKey( 115 { name: "ECDSA", namedCurve: "P-256" }, 116 false, 117 ["sign", "verify"] 118 ); 119 120 const derivedPublicKey = await crypto.subtle.getPublicKey( 121 keyPair.privateKey, 122 ["verify"] 123 ); 124 125 // Create test data 126 const data = new TextEncoder().encode("test message"); 127 128 // Sign with private key 129 const signature = await crypto.subtle.sign( 130 { name: "ECDSA", hash: "SHA-256" }, 131 keyPair.privateKey, 132 data 133 ); 134 135 // Verify with both original and derived public keys 136 const verifyOriginal = await crypto.subtle.verify( 137 { name: "ECDSA", hash: "SHA-256" }, 138 keyPair.publicKey, 139 signature, 140 data 141 ); 142 143 const verifyDerived = await crypto.subtle.verify( 144 { name: "ECDSA", hash: "SHA-256" }, 145 derivedPublicKey, 146 signature, 147 data 148 ); 149 150 assert_true(verifyOriginal, "Original public key verifies signature"); 151 assert_true(verifyDerived, "Derived public key verifies signature"); 152 153 }, "Derived public key is functionally equivalent to original public key"); 154 155 // Test with empty usages array 156 algorithms.forEach(function(algorithm) { 157 promise_test(async function(t) { 158 // Skip X25519 if not supported 159 if (algorithm.name === "X25519") { 160 try { 161 await crypto.subtle.generateKey(algorithm.generateKeyParams, false, algorithm.usages); 162 } catch (e) { 163 if (e.name === "NotSupportedError") { 164 return; 165 } 166 throw e; 167 } 168 } 169 170 const keyPair = await crypto.subtle.generateKey( 171 algorithm.generateKeyParams, 172 false, 173 algorithm.usages 174 ); 175 176 // Test with empty usages array 177 const publicKey = await crypto.subtle.getPublicKey( 178 keyPair.privateKey, 179 [] 180 ); 181 182 assert_true(publicKey instanceof CryptoKey, "getPublicKey returns a CryptoKey"); 183 assert_equals(publicKey.type, "public", "Returned key is public"); 184 assert_equals(publicKey.usages.length, 0, "Public key has no usages"); 185 186 }, `getPublicKey works with empty usages for ${algorithm.name}`); 187 }); 188 189 // Test error cases 190 191 // Test with non-private key (should throw InvalidAccessError) 192 promise_test(async function(t) { 193 const keyPair = await crypto.subtle.generateKey( 194 { name: "ECDSA", namedCurve: "P-256" }, 195 false, 196 ["sign", "verify"] 197 ); 198 199 await promise_rejects_dom(t, "InvalidAccessError", 200 crypto.subtle.getPublicKey(keyPair.publicKey, ["verify"]), 201 "getPublicKey should reject when called with a public key" 202 ); 203 }, "getPublicKey rejects with InvalidAccessError when given a public key"); 204 205 // Test with symmetric keys (should throw NotSupportedError for non-private keys) 206 promise_test(async function(t) { 207 const aesKey = await crypto.subtle.generateKey( 208 { name: "AES-GCM", length: 256 }, 209 false, 210 ["encrypt", "decrypt"] 211 ); 212 213 await promise_rejects_dom(t, "NotSupportedError", 214 crypto.subtle.getPublicKey(aesKey, []), 215 "getPublicKey should reject AES-GCM keys" 216 ); 217 }, "getPublicKey rejects with NotSupportedError for AES-GCM symmetric keys"); 218 219 promise_test(async function(t) { 220 const hmacKey = await crypto.subtle.generateKey( 221 { name: "HMAC", hash: "SHA-256" }, 222 false, 223 ["sign", "verify"] 224 ); 225 226 await promise_rejects_dom(t, "NotSupportedError", 227 crypto.subtle.getPublicKey(hmacKey, []), 228 "getPublicKey should reject HMAC keys" 229 ); 230 }, "getPublicKey rejects with NotSupportedError for HMAC symmetric keys"); 231 232 // Test with invalid usages for the algorithm 233 promise_test(async function(t) { 234 const keyPair = await crypto.subtle.generateKey( 235 { name: "ECDSA", namedCurve: "P-256" }, 236 false, 237 ["sign", "verify"] 238 ); 239 240 // Try to use "encrypt" usage with ECDSA (not supported for ECDSA public keys) 241 await promise_rejects_dom(t, "SyntaxError", 242 crypto.subtle.getPublicKey(keyPair.privateKey, ["encrypt"]), 243 "getPublicKey should reject invalid usages for the algorithm" 244 ); 245 }, "getPublicKey rejects with SyntaxError for invalid usages"); 246 247 // Test with mixed valid and invalid usages 248 promise_test(async function(t) { 249 const keyPair = await crypto.subtle.generateKey( 250 { name: "ECDSA", namedCurve: "P-256" }, 251 false, 252 ["sign", "verify"] 253 ); 254 255 // Mix valid ("verify") and invalid ("encrypt") usages 256 await promise_rejects_dom(t, "SyntaxError", 257 crypto.subtle.getPublicKey(keyPair.privateKey, ["verify", "encrypt"]), 258 "getPublicKey should reject when any usage is invalid" 259 ); 260 }, "getPublicKey rejects with SyntaxError when any usage is invalid for the algorithm"); 261 262 // Test that the method exists 263 test(function() { 264 assert_true("getPublicKey" in crypto.subtle, "getPublicKey method exists on SubtleCrypto"); 265 assert_equals(typeof crypto.subtle.getPublicKey, "function", "getPublicKey is a function"); 266 }, "getPublicKey method is available");