UNPKG

@microsoft/dev-tunnels-ssh

Version:
212 lines 8.59 kB
"use strict"; // // Copyright (c) Microsoft Corporation. All rights reserved. // Object.defineProperty(exports, "__esModule", { value: true }); exports.WebRsa = void 0; const buffer_1 = require("buffer"); const publicKeyAlgorithm_1 = require("../publicKeyAlgorithm"); const webHmac_1 = require("./webHmac"); const sshData_1 = require("../../io/sshData"); const jsonWebKeyFormatter_1 = require("./jsonWebKeyFormatter"); // Note this is exposed as an inner-class property below: `WebRsa.KeyPair`. // TypeScript requires that the class definition comes first. class WebRsaKeyPair { /* @internal */ constructor(hashAlgorithm) { this.hashAlgorithm = hashAlgorithm; this.comment = null; } get hasPublicKey() { return !!this.publicKey; } get hasPrivateKey() { return !!this.privateKey; } get keyAlgorithmName() { return WebRsa.keyAlgorithmName; } async generate(keySizeInBits) { keySizeInBits = keySizeInBits !== null && keySizeInBits !== void 0 ? keySizeInBits : WebRsaKeyPair.defaultKeySize; try { const keyGenParams = { name: 'RSASSA-PKCS1-v1_5', modulusLength: keySizeInBits, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: this.hashAlgorithm }, }; const keyPair = (await crypto.subtle.generateKey(keyGenParams, true, ['sign', 'verify'])); this.publicKey = keyPair.publicKey; this.privateKey = keyPair.privateKey; } catch (e) { throw new Error('Failed to generate RSA key pair: ' + e); } } async setPublicKeyBytes(keyBytes) { if (!keyBytes) { throw new TypeError('Buffer is required.'); } // Read public key in SSH format. const reader = new sshData_1.SshDataReader(keyBytes); const algorithmName = reader.readString('ascii'); if (algorithmName !== this.keyAlgorithmName && algorithmName !== WebRsa.rsaWithSha256 && algorithmName !== WebRsa.rsaWithSha512) { throw new Error(`Invalid RSA key algorithm: ${algorithmName}`); } const exponent = reader.readBigInt(); const modulus = reader.readBigInt(); // Import public key in JWK format. const jwk = jsonWebKeyFormatter_1.JsonWebKeyFormatter.formatRsa({ modulus, exponent }, false); jwk.alg = 'RS' + this.hashAlgorithm.replace('SHA-', ''); jwk.key_ops = ['verify']; try { const importParams = { name: 'RSASSA-PKCS1-v1_5', hash: { name: this.hashAlgorithm }, }; this.publicKey = await crypto.subtle.importKey('jwk', jwk, importParams, true, ['verify']); } catch (e) { throw new Error('Failed to import RSA public key: ' + e); } } async getPublicKeyBytes(algorithmName) { if (!this.publicKey) { return null; } if (!algorithmName) { algorithmName = this.keyAlgorithmName; } // Export public key in JWK format. let jwk; try { jwk = await crypto.subtle.exportKey('jwk', this.publicKey); } catch (e) { throw new Error('Failed to export RSA public key: ' + e); } const { modulus, exponent } = jsonWebKeyFormatter_1.JsonWebKeyFormatter.parseRsa(jwk, false); // Write public key in SSH format. const keyBuffer = buffer_1.Buffer.alloc(512); const keyWriter = new sshData_1.SshDataWriter(keyBuffer); keyWriter.writeString(algorithmName, 'ascii'); keyWriter.writeBigInt(exponent); keyWriter.writeBigInt(modulus); const keyBytes = keyWriter.toBuffer(); return keyBytes; } async importParameters(parameters) { const privateJwk = parameters.d ? jsonWebKeyFormatter_1.JsonWebKeyFormatter.formatRsa(parameters, true) : null; const publicJwk = jsonWebKeyFormatter_1.JsonWebKeyFormatter.formatRsa(parameters, false); const importParams = { name: 'RSASSA-PKCS1-v1_5', hash: { name: this.hashAlgorithm }, }; try { this.publicKey = await crypto.subtle.importKey('jwk', publicJwk, importParams, true, [ 'verify', ]); if (privateJwk) { this.privateKey = await crypto.subtle.importKey('jwk', privateJwk, importParams, true, [ 'sign', ]); } else { this.privateKey = undefined; } } catch (e) { if (!(e instanceof Error)) throw e; throw new Error('Failed to import RSA key pair: ' + e.message); } } async exportParameters() { var _a; if (!this.publicKey) throw new Error('Public key not set.'); let jwk; try { jwk = await crypto.subtle.exportKey('jwk', (_a = this.privateKey) !== null && _a !== void 0 ? _a : this.publicKey); } catch (e) { if (!(e instanceof Error)) throw e; throw new Error('Failed to export RSA public key: ' + e.message); } return jsonWebKeyFormatter_1.JsonWebKeyFormatter.parseRsa(jwk, !!this.privateKey); } dispose() { } } WebRsaKeyPair.defaultKeySize = 2048; class WebRsa extends publicKeyAlgorithm_1.PublicKeyAlgorithm { constructor(name, hashAlgorithmName) { super(name, WebRsa.keyAlgorithmName, hashAlgorithmName); } createKeyPair() { const hashAlgorithm = WebRsa.convertHashAlgorithmName(this.hashAlgorithmName); return new WebRsaKeyPair(hashAlgorithm); } async generateKeyPair(keySizeInBits) { const hashAlgorithm = WebRsa.convertHashAlgorithmName(this.hashAlgorithmName); const rsaKey = new WebRsaKeyPair(hashAlgorithm); await rsaKey.generate(keySizeInBits); return rsaKey; } createSigner(keyPair) { if (!(keyPair instanceof WebRsaKeyPair)) { throw new TypeError('RSA key pair object expected.'); } const hashAlgorithm = WebRsa.convertHashAlgorithmName(this.hashAlgorithmName); return new WebRsaSignerVerifier(keyPair, hashAlgorithm, webHmac_1.WebHmac.getHashDigestLength(this.hashAlgorithmName)); } createVerifier(keyPair) { if (!(keyPair instanceof WebRsaKeyPair)) { throw new TypeError('RSA key pair object expected.'); } const hashAlgorithm = WebRsa.convertHashAlgorithmName(this.hashAlgorithmName); return new WebRsaSignerVerifier(keyPair, hashAlgorithm, webHmac_1.WebHmac.getHashDigestLength(this.hashAlgorithmName)); } static convertHashAlgorithmName(hashAlgorithmName) { return hashAlgorithmName.replace('SHA2-', 'SHA-'); } } exports.WebRsa = WebRsa; WebRsa.keyAlgorithmName = 'ssh-rsa'; WebRsa.rsaWithSha256 = 'rsa-sha2-256'; WebRsa.rsaWithSha512 = 'rsa-sha2-512'; WebRsa.KeyPair = WebRsaKeyPair; class WebRsaSignerVerifier { constructor(keyPair, hashAlgorithm, digestLength) { this.keyPair = keyPair; this.hashAlgorithm = hashAlgorithm; this.digestLength = digestLength; } async sign(data) { if (!this.keyPair.privateKey) { throw new Error('Private key not set.'); } await this.convertKeyHashAlgorithm(); const signature = buffer_1.Buffer.from(await crypto.subtle.sign('RSASSA-PKCS1-v1_5', this.keyPair.privateKey, data)); return signature; } async verify(data, signature) { if (!this.keyPair.publicKey) { throw new Error('Public key not set.'); } await this.convertKeyHashAlgorithm(); const result = await crypto.subtle.verify('RSASSA-PKCS1-v1_5', this.keyPair.publicKey, signature, data); return result; } async convertKeyHashAlgorithm() { if (this.keyPair.hashAlgorithm !== this.hashAlgorithm) { const parameters = await this.keyPair.exportParameters(); this.keyPair = new WebRsaKeyPair(this.hashAlgorithm); await this.keyPair.importParameters(parameters); } } dispose() { } } //# sourceMappingURL=webRsa.js.map