Path: blob/main/src/vs/platform/extensionManagement/node/extensionSignatureVerificationService.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { getErrorMessage } from '../../../base/common/errors.js';6import { isDefined } from '../../../base/common/types.js';7import { TargetPlatform } from '../../extensions/common/extensions.js';8import { createDecorator } from '../../instantiation/common/instantiation.js';9import { ILogService, LogLevel } from '../../log/common/log.js';10import { ITelemetryService } from '../../telemetry/common/telemetry.js';11import { ExtensionSignatureVerificationCode } from '../common/extensionManagement.js';1213export const IExtensionSignatureVerificationService = createDecorator<IExtensionSignatureVerificationService>('IExtensionSignatureVerificationService');1415export interface IExtensionSignatureVerificationResult {16readonly code: ExtensionSignatureVerificationCode;17}1819/**20* A service for verifying signed extensions.21*/22export interface IExtensionSignatureVerificationService {23readonly _serviceBrand: undefined;2425/**26* Verifies an extension file (.vsix) against a signature archive file.27* @param extensionId The extension identifier.28* @param version The extension version.29* @param vsixFilePath The extension file path.30* @param signatureArchiveFilePath The signature archive file path.31* @returns returns the verification result or undefined if the verification was not executed.32*/33verify(extensionId: string, version: string, vsixFilePath: string, signatureArchiveFilePath: string, clientTargetPlatform?: TargetPlatform): Promise<IExtensionSignatureVerificationResult | undefined>;34}3536declare module vsceSign {37export function verify(vsixFilePath: string, signatureArchiveFilePath: string, verbose: boolean): Promise<ExtensionSignatureVerificationResult>;38}3940/**41* Extension signature verification result42*/43export interface ExtensionSignatureVerificationResult {44readonly code: ExtensionSignatureVerificationCode;45readonly didExecute: boolean;46readonly internalCode?: number;47readonly output?: string;48}4950export class ExtensionSignatureVerificationService implements IExtensionSignatureVerificationService {51declare readonly _serviceBrand: undefined;5253private moduleLoadingPromise: Promise<typeof vsceSign> | undefined;5455constructor(56@ILogService private readonly logService: ILogService,57@ITelemetryService private readonly telemetryService: ITelemetryService,58) { }5960private vsceSign(): Promise<typeof vsceSign> {61if (!this.moduleLoadingPromise) {62this.moduleLoadingPromise = this.resolveVsceSign();63}6465return this.moduleLoadingPromise;66}6768private async resolveVsceSign(): Promise<typeof vsceSign> {69const mod = '@vscode/vsce-sign';70return import(mod);71}7273public async verify(extensionId: string, version: string, vsixFilePath: string, signatureArchiveFilePath: string, clientTargetPlatform?: TargetPlatform): Promise<IExtensionSignatureVerificationResult | undefined> {74let module: typeof vsceSign;7576try {77module = await this.vsceSign();78} catch (error) {79this.logService.error('Could not load vsce-sign module', getErrorMessage(error));80this.logService.info(`Extension signature verification is not done: ${extensionId}`);81return undefined;82}8384const startTime = new Date().getTime();85let result: ExtensionSignatureVerificationResult;8687try {88this.logService.trace(`Verifying extension signature for ${extensionId}...`);89result = await module.verify(vsixFilePath, signatureArchiveFilePath, this.logService.getLevel() === LogLevel.Trace);90} catch (e) {91result = {92code: ExtensionSignatureVerificationCode.UnknownError,93didExecute: false,94output: getErrorMessage(e)95};96}9798const duration = new Date().getTime() - startTime;99100this.logService.info(`Extension signature verification result for ${extensionId}: ${result.code}. ${isDefined(result.internalCode) ? `Internal Code: ${result.internalCode}. ` : ''}Executed: ${result.didExecute}. Duration: ${duration}ms.`);101this.logService.trace(`Extension signature verification output for ${extensionId}:\n${result.output}`);102103type ExtensionSignatureVerificationClassification = {104owner: 'sandy081';105comment: 'Extension signature verification event';106extensionId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'extension identifier' };107extensionVersion: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'extension version' };108code: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'result code of the verification' };109internalCode?: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; 'isMeasurement': true; comment: 'internal code of the verification' };110duration: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; 'isMeasurement': true; comment: 'amount of time taken to verify the signature' };111didExecute: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'whether the verification was executed' };112clientTargetPlatform?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'target platform of the client' };113};114type ExtensionSignatureVerificationEvent = {115extensionId: string;116extensionVersion: string;117code: string;118internalCode?: number;119duration: number;120didExecute: boolean;121clientTargetPlatform?: string;122};123this.telemetryService.publicLog2<ExtensionSignatureVerificationEvent, ExtensionSignatureVerificationClassification>('extensionsignature:verification', {124extensionId,125extensionVersion: version,126code: result.code,127internalCode: result.internalCode,128duration,129didExecute: result.didExecute,130clientTargetPlatform,131});132133return { code: result.code };134}135}136137138