"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=https://github.com/VSCodium/sourcemaps/releases/download/stable-824c4c46a288b839f13b24022655329c2aeb9f81/node_modules-@microsoft-dev-tunnels-ssh-algorithms-web-webRsa.js.map