UNPKG

@sphereon/ssi-sdk-ext.x509-utils

Version:

Sphereon SSI-SDK plugin functions for X.509 Certificate handling.

89 lines (75 loc) 3.13 kB
// @ts-ignore import { KeyUsage, CryptoKey, RsaHashedImportParams, RsaHashedKeyGenParams } from 'node' // @ts-ignore import * as u8a from 'uint8arrays' const { toString } = u8a import type { HashAlgorithm } from '../types' import { globalCrypto } from './crypto' import { derToPEM } from './x509-utils' import type { JsonWebKey } from '@sphereon/ssi-types' export type RSASignatureSchemes = 'RSASSA-PKCS1-V1_5' | 'RSA-PSS' export type RSAEncryptionSchemes = 'RSAES-PKCS-v1_5 ' | 'RSAES-OAEP' const usage = (jwk: JsonWebKey): KeyUsage[] => { if (jwk.key_ops && jwk.key_ops.length > 0) { return jwk.key_ops as KeyUsage[] } if (jwk.use) { const usages: KeyUsage[] = [] if (jwk.use.includes('sig')) { usages.push('sign', 'verify') } else if (jwk.use.includes('enc')) { usages.push('encrypt', 'decrypt') } if (usages.length > 0) { return usages } } if (jwk.kty === 'RSA') { if (jwk.d) { return jwk.alg?.toUpperCase()?.includes('QAEP') ? ['encrypt'] : ['sign'] } return jwk.alg?.toUpperCase()?.includes('QAEP') ? ['decrypt'] : ['verify'] } // "decrypt" | "deriveBits" | "deriveKey" | "encrypt" | "sign" | "unwrapKey" | "verify" | "wrapKey"; return jwk.d && jwk.kty !== 'RSA' ? ['sign', 'decrypt', 'verify', 'encrypt'] : ['verify'] } export const signAlgorithmToSchemeAndHashAlg = (signingAlg: string) => { const alg = signingAlg.toUpperCase() let scheme: RSAEncryptionSchemes | RSASignatureSchemes if (alg.startsWith('RS')) { scheme = 'RSASSA-PKCS1-V1_5' } else if (alg.startsWith('PS')) { scheme = 'RSA-PSS' } else { throw Error(`Invalid signing algorithm supplied ${signingAlg}`) } const hashAlgorithm = `SHA-${alg.substring(2)}` as HashAlgorithm return { scheme, hashAlgorithm } } export const cryptoSubtleImportRSAKey = async ( jwk: JsonWebKey, scheme: RSAEncryptionSchemes | RSASignatureSchemes, hashAlgorithm?: HashAlgorithm, ): Promise<CryptoKey> => { const hashName = hashAlgorithm ? hashAlgorithm : jwk.alg ? `SHA-${jwk.alg.substring(2)}` : 'SHA-256' const importParams: RsaHashedImportParams = { name: scheme, hash: hashName } return await globalCrypto(false).subtle.importKey('jwk', jwk as JsonWebKey, importParams, false, usage(jwk)) } export const generateRSAKeyAsPEM = async ( scheme: RSAEncryptionSchemes | RSASignatureSchemes, hashAlgorithm?: HashAlgorithm, modulusLength?: number, ): Promise<string> => { const hashName = hashAlgorithm ? hashAlgorithm : 'SHA-256' const params: RsaHashedKeyGenParams = { name: scheme, hash: hashName, modulusLength: modulusLength ? modulusLength : 2048, publicExponent: new Uint8Array([1, 0, 1]), } const keyUsage: KeyUsage[] = scheme === 'RSA-PSS' || scheme === 'RSASSA-PKCS1-V1_5' ? ['sign', 'verify'] : ['encrypt', 'decrypt'] const keypair = await globalCrypto(false).subtle.generateKey(params, true, keyUsage) const pkcs8 = await globalCrypto(false).subtle.exportKey('pkcs8', keypair.privateKey) const uint8Array = new Uint8Array(pkcs8) return derToPEM(toString(uint8Array, 'base64pad'), 'RSA PRIVATE KEY') }