简体   繁体   中英

How to convert JWK to PEM in NodeJS/Typescript

I'd like to download public key from jwk endpoint and convert it into pem format that is required in sing function for jwt .

export type Secret =
    | string
    | Buffer
    | { key: string | Buffer; passphrase: string };

The jwk format can be imported with subtle from crypto as the webKey of JsonWebKey type and returned as CryptoKey

const pubKey = await subtle.importKey(
    "jwk",
    webKey,
    { hash: 'SHA-256', name: 'RSA-OAEP' },
    true,
    []
  );

The CryptoKey can be exported with subtle.exportKey but the result is in ByteArray and converting it to pem with 1. converting bytes to chars then 2. to base64 and adding it to -----BEGIN PUBLIC KEY----- with envelope with adding new line every 64 characters produces an invalid key .

/**
 * Exports the given key into the specified format, if supported.
 *
 * If the `<CryptoKey>` is not extractable, the returned promise will reject.
 *
 * When `format` is either `'pkcs8'` or `'spki'` and the export is successful,
 * the returned promise will be resolved with an `<ArrayBuffer>` containing the exported key data.
 *
 * When `format` is `'jwk'` and the export is successful, the returned promise will be resolved with a
 * JavaScript object conforming to the {@link https://tools.ietf.org/html/rfc7517 JSON Web Key} specification.
 * @param format Must be one of `'raw'`, `'pkcs8'`, `'spki'`, or `'jwk'`.
 * @returns `<Promise>` containing `<ArrayBuffer>`.
 * @since v15.0.0
 */
exportKey(format: 'jwk', key: CryptoKey): Promise<JsonWebKey>;
exportKey(format: Exclude<KeyFormat, 'jwk'>, key: CryptoKey): Promise<ArrayBuffer>;

Also, the pub key can be exported only to spki and jwk the raw is not supported.

The question in how to convert jwk to pem as simply as possible?!

The trick is converting CryptoKey to KeyObject with static from(key: webcrypto.CryptoKey): KeyObject; and then use export(options: KeyExportOptions<'pem'>): string | Buffer; export(options: KeyExportOptions<'pem'>): string | Buffer; that is member of KeyObject .

The function would be

export async function jwkToPem(webKey: JsonWebKey): Promise<string> {
  const cryptoKey = await subtle.importKey(
    "jwk",
    webKey,
    { hash: 'SHA-256', name: 'RSA-OAEP' },
    true,
    []
  );

  return KeyObject.from(cryptoKey).export({ format: "pem", type: "pkcs1"}).toString();
}

Topaco's suggestion

It could be even easier using createPublicKey that accepts JsonWebKeyInput and produces KeyObject that could be easily exported.

    /**
     * Creates and returns a new key object containing a public key. If `key` is a
     * string or `Buffer`, `format` is assumed to be `'pem'`; if `key` is a `KeyObject`with type `'private'`, the public key is derived from the given private key;
     * otherwise, `key` must be an object with the properties described above.
     *
     * If the format is `'pem'`, the `'key'` may also be an X.509 certificate.
     *
     * Because public keys can be derived from private keys, a private key may be
     * passed instead of a public key. In that case, this function behaves as if {@link createPrivateKey} had been called, except that the type of the
     * returned `KeyObject` will be `'public'` and that the private key cannot be
     * extracted from the returned `KeyObject`. Similarly, if a `KeyObject` with type`'private'` is given, a new `KeyObject` with type `'public'` will be returned
     * and it will be impossible to extract the private key from the returned object.
     * @since v11.6.0
     */
    function createPublicKey(key: PublicKeyInput | string | Buffer | KeyObject | JsonWebKeyInput): KeyObject;

then

export async function jwkToPem(webKey: JsonWebKey): Promise<string> {
  const pubKey: KeyObject = createPublicKey({
    key: webKey,
    format: 'jwk'
  });

  return pubKey.export({ format: "pem", type: "pkcs1"}).toString();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM