Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crypto.createPublicKey({ format: "jwk" }) throws a TypeError #24129

Open
dahlia opened this issue Jun 7, 2024 · 4 comments
Open

crypto.createPublicKey({ format: "jwk" }) throws a TypeError #24129

dahlia opened this issue Jun 7, 2024 · 4 comments
Labels
bug Something isn't working correctly crypto Related to node:crypto or WebCrypto node compat

Comments

@dahlia
Copy link

dahlia commented Jun 7, 2024

Version: Deno 1.44.1

Test code to reproduce:

import { createPublicKey } from "node:crypto";

const key = {
  "kty": "RSA",
  "alg": "RS256",
  "n": "5Ddosh0Bze5zy-nQ6gAJFpBfL13muCXrTyKYTps61bmnUxpp3bJnt_2N2MXGfuxBENO0Rbc8DhVPd-lNa4H3XjMwIBdxDAwW32z3pfVr8pHyWxeFtK4SCbvX8B0C6n8ZHigJsvdiCNmoj7_LO_QUzIXmXLFvEXtAqzD_hCr0pJxRIr0BrBjYwL23PkxOYzBR-URcd4Ilji6410Eh9NXycyFzKOcqZ7rjG_PnRyUX1EBZH_PN4RExjJuXYgiqhtU-tDjQFzXLhvwAd5s3ThP9lax27A6MUpjLSKkNy-dG5tlaA0QvECfDzA-5eQjcL_OfvbHlKHQH9zPh-U9Q8gsf3iXmbJrypkalUiTCqnzJu5TgZORSg6zmxNyOCz53YxBHEEaF8yROPwxWDylZfC4fxCRTdoAyFgmFLfMbiepV7AZ24KLj4jfMbGfKpkbPq0xirnSAS-3vbOfkgko5X420AttP8Z1ZBbFSD20Ath_TA9PSHiRCak4AXvOoCZg0t-WuMwzkd_B2V_JZZSTb1yBWrKTL1QzUamqlufjdWuz7M-O2Wkb2cyDSESVNuQyJgDkYb0AOWo0BaN3wbOeT_D4cSrjQoo01xQQCZHQ9SVR4QzUQNAiQcSriqEiptHYhbi6R5_GfGAeMHmlJa4atO2hense0Qk4vDc2fc-sbnQ1jPiE",
  "e": "AQAB",
  "key_ops": [
    "verify"
  ],
  "ext": true
};
const keyObject = createPublicKey({ key, format: "jwk" });

The expected result: the program successfully terminates.

The actual result:

error: Uncaught (in promise) TypeError: Invalid key type
createPublicKey({ key, format: "jwk" });
^
    at prepareAsymmetricKey (ext:deno_node/internal/crypto/keys.ts:96:13)
    at createPublicKey (ext:deno_node/internal/crypto/keys.ts:114:34)
    at file:///.../test.ts:13:1

Note that the same test code works well with Node.js and Bun.

@lucacasonato lucacasonato added bug Something isn't working correctly node compat crypto Related to node:crypto or WebCrypto labels Jun 7, 2024
@RyanFrantz
Copy link

I'm experiencing a similar issue, using openid-client in a Deno Fresh route (my OIDC callback endpoint):

An error occurred during route handling or page rendering.

  13 |         return jwk.d
  14 |             ? (0, crypto_1.createPrivateKey)({ format: 'jwk', key: jwk })
> 15 |             : (0, crypto_1.createPublicKey)({ format: 'jwk', key: jwk });
     |                                            ^
  16 |     }
  17 |     switch (jwk.kty) {
  18 |         case 'oct': {

TypeError: Invalid key type
    at prepareAsymmetricKey (ext:deno_node/internal/crypto/keys.ts:96:13)
    at createPublicKey (ext:deno_node/internal/crypto/keys.ts:114:34)
    at parse (file:///Users/rfrantz/salt-api-tokens/node_modules/.deno/jose@4.15.7/node_modules/jose/dist/node/cjs/runtime/jwk_to_key.js:15:44)
    at Object.importJWK (file:///Users/rfrantz/salt-api-tokens/node_modules/.deno/jose@4.15.7/node_modules/jose/dist/node/cjs/key/import.js:52:48)
    at Object.keyObject (file:///Users/rfrantz/salt-api-tokens/node_modules/.deno/openid-client@5.6.5/node_modules/openid-client/lib/helpers/keystore.js:243:40)
    at Client.validateJWT (file:///Users/rfrantz/salt-api-tokens/node_modules/.deno/openid-client@5.6.5/node_modules/openid-client/lib/client.js:1071:73)
    at Object.runMicrotasks (ext:core/01_core.js:642:26)
    at processTicksAndRejections (ext:deno_node/_next_tick.ts:53:10)
    at runNextTicks (ext:deno_node/_next_tick.ts:71:3)
    at eventLoopTick (ext:core/01_core.js:175:21)

My callback endpoint:

import { Handlers } from "$fresh/server.ts";
import { Issuer } from 'npm:openid-client';

const issuerUrl = 'https://keycloaktest.example.com/auth/realms/foo';
const keycloakIssuer = await Issuer.discover(issuerUrl);
const redirectUri = 'http://localhost:8000/authncb';

const client = new keycloakIssuer.Client({
  client_id: 'myclient',
  client_secret: '1234',
  redirect_uris: [redirectUri],
  response_types: ['code'],
});

export const handler: Handlers = {
  async GET(req, _ctx) {
    // Parse the query parameters sent from the authorization server, to be
    // used when processing the code exchange.
    const cbParams = client.callbackParams(req);
    const checks = {"state": "secret-state-value"};

    // This call to .callback() triggers the error above.
    const tokenSet = await client.callback(redirectUri, cbParams, checks);

    return new Response(); // Simple, empty response, for now.
  },
};

Deno version:

❯ deno --version
deno 1.44.4 (release, aarch64-apple-darwin)
v8 12.6.228.9
typescript 5.4.5

@RyanFrantz
Copy link

The value of the jwk object:

{
  "kid": "lMzPx5WmuRT1nfrylqjO0pNOFzqz-RgLBZUhGrh5YmI",
  "kty": "RSA",
  "alg": "RS256",
  "use": "sig",
  "n": "m4iarC5I4LWgOoGKNZV_0GsHNddHYLCH80zw2um-cVHqIJ3BSamDI_9rtljZ5prq_SBy5oM85LbGQHdVLhnjMT4PfHGBHDm2qpzoOPBZbjk-j6tieMWOiLe0QMIeUUfHwJZmkNvPSjjPnZzTwXklt5VYSWpDNcVdGYXLMH7u2VhShUROD-2m2RzFVUF-CHT1AN0sSFrGjm3XPDu1OyR_NZjDOlw6bTcWJi8AsFwFln9xNU_K5P_rvRznUortvOYeOjCMukUUgkU0It2Z1MTQc864GY-DgLyBMnKSqwJ8ioKshhlLodfmBmMZzl1fqwT2fEHFbZOUN8AIA2iVbEhOkQ",
  "e": "AQAB",
  "x5c": [
    "MIICpzCCAY8CBgGQbz6R1DANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxFUy1TYWx0c3RhY2swHhcNMjQwNzAxMTY1OTQ5WhcNMzQwNzAxMTcwMTI5WjAXMRUwEwYDVQQDDAxFUy1TYWx0c3RhY2swggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbiJqsLkjgtaA6gYo1lX/Qawc110dgsIfzTPDa6b5xUeogncFJqYMj/2u2WNnmmur9IHLmgzzktsZAd1UuGeMxPg98cYEcObaqnOg48FluOT6Pq2J4xY6It7RAwh5RR8fAlmaQ289KOM+dnNPBeSW3lVhJakM1xV0Zhcswfu7ZWFKFRE4P7abZHMVVQX4IdPUA3SxIWsaObdc8O7U7JH81mMM6XDptNxYmLwCwXAWWf3E1T8rk/+u9HOdSiu285h46MIy6RRSCRTQi3ZnUxNBzzrgZj4OAvIEycpKrAnyKgqyGGUuh1+YGYxnOXV+rBPZ8QcVtk5Q3wAgDaJVsSE6RAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAB6jPGwfMnqHOJL5Bga0Yz5VKtOnJcABjSNewoQSWwIOLIRxdm1pEcpYK4yxx2InhJhdUMKvHs0iNHYsnwKL9e8oGsJFUKN2/LKCeuB4J55X3qoa8iF9Sslr/SsjFrQH3DVym7Egca6+ze7j+fll/yTNF93OFB3PufGD5kJMyhgjElN6vd48qehT3lYpGqZJo/SeIXVIIk8W3ZfXVhLQtukeKzXr/rmB+mS7hYjBBKzATLl8Pn5MzsxYkUvwUpaejOyIfAHRQMuZZQdVWtn1tiRG4AdJsGc60x//WRyWjibld/LM9oIJ7n0PYCwULoAQTNrQJTo42EvPHiF8hyM0bB8="
  ],
  "x5t": "9Asesbt34tXNfBcEwV5fUe1fCTU",
  "x5t#S256": "Q8u2rgvkQ8QNIJJDRMFQCJQV9NKAyDBsTQC293BugzM"
}

@RyanFrantz
Copy link

I'm looking at prepareAsymmetricKey (ext:deno_node/internal/crypto/keys.ts:93) since that conditional gets hit before the exception is thrown. The key parameter passed into prepareAsymmetricKey() is {format: 'jwk', key: {...}}. The value of that nested key is what you see in my previous comment. This code has me hung up, though:

93:  } else if (typeof key == "object") {
94:    const { key: data, encoding, format, type } = key;
95:    if (!isStringOrBuffer(data)) {
96:      throw new TypeError("Invalid key type");
97:    }

Specifically, line 94, where the key argument is destructured into another object with a key of key. Where did data come from? Is that an implicit way to access key.key from the parameter passed into prepareAsymmetricKey()? I've not seen syntax like that before.

In any case, because data is also an object (whose contents are what's in my previous comment), it fails the test for stringiness.

@RyanFrantz
Copy link

TIL about aliasing within object destructuring. Now I understand that in my previous comment, data is an alias for key.key.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working correctly crypto Related to node:crypto or WebCrypto node compat
Projects
None yet
Development

No branches or pull requests

3 participants