/**
 * PKCS#11 Interface Wrapper
 *
 * Provides a standardized PKCS#11 interface wrapper for smart card
 * and hardware token compatibility. This module enables:
 * - Smart card authentication
 * - PIV (Personal Identity Verification) card support
 * - YubiKey HSM integration
 * - Generic PKCS#11 token access
 *
 * FIPS 140-3 Compliance Notes:
 * - All cryptographic operations are performed within the token
 * - Private keys never leave the secure boundary
 * - Supports FIPS-approved algorithms only when in FIPS mode
 *
 * @module security/hsm/pkcs11-wrapper
 */
import * as crypto from 'crypto';
import { BaseHSMProvider, KeyType, KeyUsage, ECCurve, HSMConnectionError, HSMOperationError, HSMKeyNotFoundError, HSMPermissionError, } from './provider';
// ============================================================================
// PKCS#11 Types and Constants
// ============================================================================
/**
 * PKCS#11 mechanism types
 */
export var CKM;
(function (CKM) {
    // RSA Mechanisms
    CKM[CKM["RSA_PKCS_KEY_PAIR_GEN"] = 0] = "RSA_PKCS_KEY_PAIR_GEN";
    CKM[CKM["RSA_PKCS"] = 1] = "RSA_PKCS";
    CKM[CKM["RSA_PKCS_OAEP"] = 9] = "RSA_PKCS_OAEP";
    CKM[CKM["RSA_PKCS_PSS"] = 13] = "RSA_PKCS_PSS";
    // EC Mechanisms
    CKM[CKM["EC_KEY_PAIR_GEN"] = 4160] = "EC_KEY_PAIR_GEN";
    CKM[CKM["ECDSA"] = 4161] = "ECDSA";
    CKM[CKM["ECDSA_SHA256"] = 4164] = "ECDSA_SHA256";
    CKM[CKM["ECDSA_SHA384"] = 4165] = "ECDSA_SHA384";
    CKM[CKM["ECDSA_SHA512"] = 4166] = "ECDSA_SHA512";
    CKM[CKM["ECDH1_DERIVE"] = 4176] = "ECDH1_DERIVE";
    // AES Mechanisms
    CKM[CKM["AES_KEY_GEN"] = 4224] = "AES_KEY_GEN";
    CKM[CKM["AES_CBC"] = 4226] = "AES_CBC";
    CKM[CKM["AES_CBC_PAD"] = 4229] = "AES_CBC_PAD";
    CKM[CKM["AES_GCM"] = 4231] = "AES_GCM";
    CKM[CKM["AES_KEY_WRAP"] = 8457] = "AES_KEY_WRAP";
    CKM[CKM["AES_KEY_WRAP_PAD"] = 8458] = "AES_KEY_WRAP_PAD";
    // SHA Mechanisms
    CKM[CKM["SHA256"] = 592] = "SHA256";
    CKM[CKM["SHA384"] = 608] = "SHA384";
    CKM[CKM["SHA512"] = 624] = "SHA512";
    CKM[CKM["SHA256_HMAC"] = 593] = "SHA256_HMAC";
    CKM[CKM["SHA384_HMAC"] = 609] = "SHA384_HMAC";
    CKM[CKM["SHA512_HMAC"] = 625] = "SHA512_HMAC";
    // Generic Secret Key
    CKM[CKM["GENERIC_SECRET_KEY_GEN"] = 848] = "GENERIC_SECRET_KEY_GEN";
    // EdDSA (Edwards-curve DSA)
    CKM[CKM["EDDSA"] = 2147486721] = "EDDSA";
})(CKM || (CKM = {}));
/**
 * PKCS#11 object class types
 */
export var CKO;
(function (CKO) {
    CKO[CKO["DATA"] = 0] = "DATA";
    CKO[CKO["CERTIFICATE"] = 1] = "CERTIFICATE";
    CKO[CKO["PUBLIC_KEY"] = 2] = "PUBLIC_KEY";
    CKO[CKO["PRIVATE_KEY"] = 3] = "PRIVATE_KEY";
    CKO[CKO["SECRET_KEY"] = 4] = "SECRET_KEY";
})(CKO || (CKO = {}));
/**
 * PKCS#11 key types
 */
export var CKK;
(function (CKK) {
    CKK[CKK["RSA"] = 0] = "RSA";
    CKK[CKK["DSA"] = 1] = "DSA";
    CKK[CKK["DH"] = 2] = "DH";
    CKK[CKK["EC"] = 3] = "EC";
    CKK[CKK["GENERIC_SECRET"] = 16] = "GENERIC_SECRET";
    CKK[CKK["AES"] = 31] = "AES";
    CKK[CKK["SHA256_HMAC"] = 43] = "SHA256_HMAC";
    CKK[CKK["SHA384_HMAC"] = 44] = "SHA384_HMAC";
    CKK[CKK["SHA512_HMAC"] = 45] = "SHA512_HMAC";
    CKK[CKK["EC_EDWARDS"] = 64] = "EC_EDWARDS";
})(CKK || (CKK = {}));
/**
 * PKCS#11 attribute types
 */
export var CKA;
(function (CKA) {
    CKA[CKA["CLASS"] = 0] = "CLASS";
    CKA[CKA["TOKEN"] = 1] = "TOKEN";
    CKA[CKA["PRIVATE"] = 2] = "PRIVATE";
    CKA[CKA["LABEL"] = 3] = "LABEL";
    CKA[CKA["VALUE"] = 17] = "VALUE";
    CKA[CKA["CERTIFICATE_TYPE"] = 128] = "CERTIFICATE_TYPE";
    CKA[CKA["ID"] = 258] = "ID";
    CKA[CKA["SENSITIVE"] = 259] = "SENSITIVE";
    CKA[CKA["ENCRYPT"] = 260] = "ENCRYPT";
    CKA[CKA["DECRYPT"] = 261] = "DECRYPT";
    CKA[CKA["WRAP"] = 262] = "WRAP";
    CKA[CKA["UNWRAP"] = 263] = "UNWRAP";
    CKA[CKA["SIGN"] = 264] = "SIGN";
    CKA[CKA["VERIFY"] = 266] = "VERIFY";
    CKA[CKA["DERIVE"] = 268] = "DERIVE";
    CKA[CKA["MODULUS"] = 288] = "MODULUS";
    CKA[CKA["MODULUS_BITS"] = 289] = "MODULUS_BITS";
    CKA[CKA["PUBLIC_EXPONENT"] = 290] = "PUBLIC_EXPONENT";
    CKA[CKA["EC_PARAMS"] = 384] = "EC_PARAMS";
    CKA[CKA["EC_POINT"] = 385] = "EC_POINT";
    CKA[CKA["EXTRACTABLE"] = 354] = "EXTRACTABLE";
    CKA[CKA["KEY_TYPE"] = 256] = "KEY_TYPE";
    CKA[CKA["VALUE_LEN"] = 353] = "VALUE_LEN";
})(CKA || (CKA = {}));
/**
 * PKCS#11 user types
 */
export var CKU;
(function (CKU) {
    CKU[CKU["SO"] = 0] = "SO";
    CKU[CKU["USER"] = 1] = "USER";
    CKU[CKU["CONTEXT_SPECIFIC"] = 2] = "CONTEXT_SPECIFIC";
})(CKU || (CKU = {}));
/**
 * PKCS#11 return values
 */
export var CKR;
(function (CKR) {
    CKR[CKR["OK"] = 0] = "OK";
    CKR[CKR["CANCEL"] = 1] = "CANCEL";
    CKR[CKR["HOST_MEMORY"] = 2] = "HOST_MEMORY";
    CKR[CKR["SLOT_ID_INVALID"] = 3] = "SLOT_ID_INVALID";
    CKR[CKR["GENERAL_ERROR"] = 5] = "GENERAL_ERROR";
    CKR[CKR["FUNCTION_FAILED"] = 6] = "FUNCTION_FAILED";
    CKR[CKR["ARGUMENTS_BAD"] = 7] = "ARGUMENTS_BAD";
    CKR[CKR["NO_EVENT"] = 8] = "NO_EVENT";
    CKR[CKR["ATTRIBUTE_READ_ONLY"] = 16] = "ATTRIBUTE_READ_ONLY";
    CKR[CKR["ATTRIBUTE_SENSITIVE"] = 17] = "ATTRIBUTE_SENSITIVE";
    CKR[CKR["ATTRIBUTE_TYPE_INVALID"] = 18] = "ATTRIBUTE_TYPE_INVALID";
    CKR[CKR["ATTRIBUTE_VALUE_INVALID"] = 19] = "ATTRIBUTE_VALUE_INVALID";
    CKR[CKR["DATA_INVALID"] = 32] = "DATA_INVALID";
    CKR[CKR["DATA_LEN_RANGE"] = 33] = "DATA_LEN_RANGE";
    CKR[CKR["DEVICE_ERROR"] = 48] = "DEVICE_ERROR";
    CKR[CKR["DEVICE_MEMORY"] = 49] = "DEVICE_MEMORY";
    CKR[CKR["DEVICE_REMOVED"] = 50] = "DEVICE_REMOVED";
    CKR[CKR["ENCRYPTED_DATA_INVALID"] = 64] = "ENCRYPTED_DATA_INVALID";
    CKR[CKR["ENCRYPTED_DATA_LEN_RANGE"] = 65] = "ENCRYPTED_DATA_LEN_RANGE";
    CKR[CKR["FUNCTION_CANCELED"] = 80] = "FUNCTION_CANCELED";
    CKR[CKR["FUNCTION_NOT_PARALLEL"] = 81] = "FUNCTION_NOT_PARALLEL";
    CKR[CKR["FUNCTION_NOT_SUPPORTED"] = 84] = "FUNCTION_NOT_SUPPORTED";
    CKR[CKR["KEY_HANDLE_INVALID"] = 96] = "KEY_HANDLE_INVALID";
    CKR[CKR["KEY_SIZE_RANGE"] = 98] = "KEY_SIZE_RANGE";
    CKR[CKR["KEY_TYPE_INCONSISTENT"] = 99] = "KEY_TYPE_INCONSISTENT";
    CKR[CKR["KEY_NOT_NEEDED"] = 100] = "KEY_NOT_NEEDED";
    CKR[CKR["KEY_CHANGED"] = 101] = "KEY_CHANGED";
    CKR[CKR["KEY_NEEDED"] = 102] = "KEY_NEEDED";
    CKR[CKR["KEY_INDIGESTIBLE"] = 103] = "KEY_INDIGESTIBLE";
    CKR[CKR["KEY_FUNCTION_NOT_PERMITTED"] = 104] = "KEY_FUNCTION_NOT_PERMITTED";
    CKR[CKR["KEY_NOT_WRAPPABLE"] = 105] = "KEY_NOT_WRAPPABLE";
    CKR[CKR["KEY_UNEXTRACTABLE"] = 106] = "KEY_UNEXTRACTABLE";
    CKR[CKR["MECHANISM_INVALID"] = 112] = "MECHANISM_INVALID";
    CKR[CKR["MECHANISM_PARAM_INVALID"] = 113] = "MECHANISM_PARAM_INVALID";
    CKR[CKR["PIN_INCORRECT"] = 160] = "PIN_INCORRECT";
    CKR[CKR["PIN_INVALID"] = 161] = "PIN_INVALID";
    CKR[CKR["PIN_LEN_RANGE"] = 162] = "PIN_LEN_RANGE";
    CKR[CKR["PIN_EXPIRED"] = 163] = "PIN_EXPIRED";
    CKR[CKR["PIN_LOCKED"] = 164] = "PIN_LOCKED";
    CKR[CKR["SESSION_CLOSED"] = 176] = "SESSION_CLOSED";
    CKR[CKR["SESSION_COUNT"] = 177] = "SESSION_COUNT";
    CKR[CKR["SESSION_HANDLE_INVALID"] = 179] = "SESSION_HANDLE_INVALID";
    CKR[CKR["SESSION_PARALLEL_NOT_SUPPORTED"] = 180] = "SESSION_PARALLEL_NOT_SUPPORTED";
    CKR[CKR["SESSION_READ_ONLY"] = 181] = "SESSION_READ_ONLY";
    CKR[CKR["SESSION_EXISTS"] = 182] = "SESSION_EXISTS";
    CKR[CKR["SESSION_READ_ONLY_EXISTS"] = 183] = "SESSION_READ_ONLY_EXISTS";
    CKR[CKR["SESSION_READ_WRITE_SO_EXISTS"] = 184] = "SESSION_READ_WRITE_SO_EXISTS";
    CKR[CKR["SIGNATURE_INVALID"] = 192] = "SIGNATURE_INVALID";
    CKR[CKR["SIGNATURE_LEN_RANGE"] = 193] = "SIGNATURE_LEN_RANGE";
    CKR[CKR["TOKEN_NOT_PRESENT"] = 224] = "TOKEN_NOT_PRESENT";
    CKR[CKR["TOKEN_NOT_RECOGNIZED"] = 225] = "TOKEN_NOT_RECOGNIZED";
    CKR[CKR["TOKEN_WRITE_PROTECTED"] = 226] = "TOKEN_WRITE_PROTECTED";
    CKR[CKR["USER_ALREADY_LOGGED_IN"] = 256] = "USER_ALREADY_LOGGED_IN";
    CKR[CKR["USER_NOT_LOGGED_IN"] = 257] = "USER_NOT_LOGGED_IN";
    CKR[CKR["USER_PIN_NOT_INITIALIZED"] = 258] = "USER_PIN_NOT_INITIALIZED";
    CKR[CKR["USER_TYPE_INVALID"] = 259] = "USER_TYPE_INVALID";
    CKR[CKR["CRYPTOKI_NOT_INITIALIZED"] = 400] = "CRYPTOKI_NOT_INITIALIZED";
    CKR[CKR["CRYPTOKI_ALREADY_INITIALIZED"] = 401] = "CRYPTOKI_ALREADY_INITIALIZED";
})(CKR || (CKR = {}));
// ============================================================================
// PKCS#11 Wrapper Provider
// ============================================================================
/**
 * PKCS#11 wrapper for smart cards and hardware tokens
 */
export class PKCS11WrapperProvider extends BaseHSMProvider {
    name = 'PKCS#11 Token';
    isProduction = true;
    pkcs11Config;
    session = null;
    objectHandles = new Map();
    handleCounter = 1;
    fipsMode;
    // Simulated library state
    initialized = false;
    slots = [];
    tokenInfo = null;
    mechanisms = new Map();
    constructor(config) {
        super(config);
        this.pkcs11Config = config;
        this.fipsMode = config.fipsMode ?? false;
    }
    // ============================================================================
    // Connection Management
    // ============================================================================
    /**
     * Initialize and connect to PKCS#11 token
     */
    async connect() {
        try {
            this.logAudit({
                operation: 'connect',
                success: false,
                metadata: { libraryPath: this.pkcs11Config.libraryPath },
            });
            // Initialize PKCS#11 library
            await this.initializeLibrary();
            // Find and select slot
            const slotId = await this.selectSlot();
            // Open session
            const sessionHandle = await this.openSession(slotId);
            this.session = {
                handle: sessionHandle,
                slotId,
                readWrite: !this.pkcs11Config.readOnly,
                loggedIn: false,
            };
            // Login if PIN provided
            if (this.pkcs11Config.userPin) {
                await this.login(CKU.USER, this.pkcs11Config.userPin);
            }
            this.connected = true;
            // Enumerate existing objects
            await this.enumerateObjects();
            this.logAudit({
                operation: 'connect',
                success: true,
                metadata: { slotId, fipsMode: this.fipsMode },
            });
            this.emit('connected', { provider: this.name, slotId });
        }
        catch (error) {
            const err = error instanceof Error ? error : new Error(String(error));
            this.logAudit({
                operation: 'connect',
                success: false,
                errorMessage: err.message,
            });
            throw new HSMConnectionError(`Failed to connect to PKCS#11 token: ${err.message}`, this.name, err);
        }
    }
    /**
     * Initialize PKCS#11 library (C_Initialize)
     */
    async initializeLibrary() {
        // In real implementation:
        // const pkcs11 = new PKCS11Module(this.pkcs11Config.libraryPath);
        // pkcs11.C_Initialize({ flags: CKF_OS_LOCKING_OK });
        // Simulate library initialization
        this.initialized = true;
        // Populate simulated slot list
        this.slots = [
            {
                slotId: 0,
                slotDescription: 'Virtual Smart Card Slot 0',
                manufacturerId: 'Vorion Security',
                flags: 0x07, // CKF_TOKEN_PRESENT | CKF_REMOVABLE_DEVICE | CKF_HW_SLOT
                hardwareVersion: { major: 1, minor: 0 },
                firmwareVersion: { major: 1, minor: 0 },
                tokenPresent: true,
            },
        ];
        // Set up token info
        this.tokenInfo = {
            label: 'Vorion PKCS#11 Token',
            manufacturerId: 'Vorion Security',
            model: 'Virtual HSM',
            serialNumber: crypto.randomBytes(8).toString('hex').toUpperCase(),
            flags: 0x405, // CKF_RNG | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED
            maxSessionCount: 64,
            sessionCount: 0,
            maxRwSessionCount: 32,
            rwSessionCount: 0,
            maxPinLen: 32,
            minPinLen: 4,
            totalPublicMemory: 65536,
            freePublicMemory: 65536,
            totalPrivateMemory: 32768,
            freePrivateMemory: 32768,
            hardwareVersion: { major: 2, minor: 40 },
            firmwareVersion: { major: 2, minor: 40 },
        };
        // Populate supported mechanisms
        this.mechanisms.set(0, [
            { mechanism: CKM.RSA_PKCS_KEY_PAIR_GEN, minKeySize: 2048, maxKeySize: 4096, flags: 0x10001 },
            { mechanism: CKM.RSA_PKCS_PSS, minKeySize: 2048, maxKeySize: 4096, flags: 0x10001 },
            { mechanism: CKM.EC_KEY_PAIR_GEN, minKeySize: 256, maxKeySize: 521, flags: 0x10001 },
            { mechanism: CKM.ECDSA_SHA256, minKeySize: 256, maxKeySize: 521, flags: 0x10001 },
            { mechanism: CKM.AES_KEY_GEN, minKeySize: 128, maxKeySize: 256, flags: 0x8001 },
            { mechanism: CKM.AES_GCM, minKeySize: 128, maxKeySize: 256, flags: 0x8001 },
            { mechanism: CKM.SHA256_HMAC, minKeySize: 256, maxKeySize: 512, flags: 0x8001 },
        ]);
        this.emit('libraryInitialized', { libraryPath: this.pkcs11Config.libraryPath });
    }
    /**
     * Select slot to use
     */
    async selectSlot() {
        // C_GetSlotList(TRUE, slots, &count)
        if (this.slots.length === 0) {
            throw new Error('No PKCS#11 slots available');
        }
        // If slot specified in config, find it
        if (this.pkcs11Config.slot !== undefined) {
            if (typeof this.pkcs11Config.slot === 'number') {
                const slot = this.slots.find(s => s.slotId === this.pkcs11Config.slot);
                if (!slot) {
                    throw new Error(`Slot ${this.pkcs11Config.slot} not found`);
                }
                return slot.slotId;
            }
            else {
                // Find by label
                // In real implementation, check token label
                return this.slots[0].slotId;
            }
        }
        // Default to first slot with token present
        const slotWithToken = this.slots.find(s => s.tokenPresent);
        if (!slotWithToken) {
            throw new Error('No token present in any slot');
        }
        return slotWithToken.slotId;
    }
    /**
     * Open PKCS#11 session (C_OpenSession)
     */
    async openSession(slotId) {
        // C_OpenSession(slotId, flags, &sessionHandle)
        const sessionHandle = this.handleCounter++;
        if (this.tokenInfo) {
            this.tokenInfo.sessionCount++;
            if (!this.pkcs11Config.readOnly) {
                this.tokenInfo.rwSessionCount++;
            }
        }
        return sessionHandle;
    }
    /**
     * Login to token (C_Login)
     */
    async login(userType, pin) {
        if (!this.session) {
            throw new Error('No session open');
        }
        // C_Login(session, userType, pin, pinLen)
        // Simulate PIN verification
        if (pin.length < (this.tokenInfo?.minPinLen ?? 4)) {
            throw new HSMPermissionError('PIN too short', this.name);
        }
        this.session.loggedIn = true;
        this.session.userType = userType;
        this.logAudit({
            operation: 'login',
            success: true,
            metadata: { userType: CKU[userType] },
        });
    }
    /**
     * Enumerate objects in token
     */
    async enumerateObjects() {
        // C_FindObjectsInit, C_FindObjects, C_FindObjectsFinal
        // In real implementation, query all objects
        // For simulation, start empty
    }
    /**
     * Disconnect from token
     */
    async disconnect() {
        if (this.session) {
            if (this.session.loggedIn) {
                // C_Logout
                this.session.loggedIn = false;
            }
            // C_CloseSession
            if (this.tokenInfo) {
                this.tokenInfo.sessionCount--;
                if (this.session.readWrite) {
                    this.tokenInfo.rwSessionCount--;
                }
            }
            this.session = null;
        }
        if (this.initialized) {
            // C_Finalize
            this.initialized = false;
        }
        this.connected = false;
        this.logAudit({
            operation: 'disconnect',
            success: true,
        });
        this.emit('disconnected', { provider: this.name });
    }
    /**
     * Get HSM status
     */
    async getStatus() {
        return {
            connected: this.connected,
            healthy: this.connected && this.session?.loggedIn === true,
            provider: this.name,
            version: this.tokenInfo?.firmwareVersion
                ? `${this.tokenInfo.firmwareVersion.major}.${this.tokenInfo.firmwareVersion.minor}`
                : '0.0',
            freeSlots: this.tokenInfo?.freePrivateMemory,
            usedSlots: this.objectHandles.size,
            lastHealthCheck: new Date(),
        };
    }
    // ============================================================================
    // Key Generation
    // ============================================================================
    /**
     * Generate key using PKCS#11
     */
    async generateKey(spec) {
        this.ensureConnected();
        this.validateKeySpec(spec);
        this.validateFIPSCompliance(spec);
        const keyId = spec.id || this.generateKeyId();
        try {
            let publicKey;
            let mechanism;
            switch (spec.type) {
                case KeyType.AES:
                    mechanism = CKM.AES_KEY_GEN;
                    await this.generateSymmetricKey(keyId, spec, mechanism);
                    break;
                case KeyType.RSA:
                    mechanism = CKM.RSA_PKCS_KEY_PAIR_GEN;
                    publicKey = await this.generateKeyPair(keyId, spec, mechanism);
                    break;
                case KeyType.EC:
                    mechanism = CKM.EC_KEY_PAIR_GEN;
                    publicKey = await this.generateKeyPair(keyId, spec, mechanism);
                    break;
                case KeyType.HMAC:
                    mechanism = CKM.GENERIC_SECRET_KEY_GEN;
                    await this.generateSymmetricKey(keyId, spec, mechanism);
                    break;
                default:
                    throw new Error(`Unsupported key type for PKCS#11: ${spec.type}`);
            }
            const keyHandle = {
                id: keyId,
                label: spec.label,
                type: spec.type,
                size: spec.size,
                curve: spec.curve,
                usage: spec.usage,
                extractable: spec.extractable,
                createdAt: new Date(),
                expiresAt: spec.expiresAt,
                publicKey,
                metadata: {
                    pkcs11: true,
                    fipsMode: this.fipsMode,
                },
            };
            this.keys.set(keyId, keyHandle);
            this.logAudit({
                operation: 'generateKey',
                keyId,
                success: true,
                metadata: { type: spec.type, mechanism: CKM[mechanism] },
            });
            return keyHandle;
        }
        catch (error) {
            const err = error instanceof Error ? error : new Error(String(error));
            this.logAudit({
                operation: 'generateKey',
                success: false,
                errorMessage: err.message,
            });
            throw new HSMOperationError('generateKey', err.message, this.name, err);
        }
    }
    /**
     * Validate FIPS compliance of key spec
     */
    validateFIPSCompliance(spec) {
        if (!this.fipsMode)
            return;
        // FIPS 140-3 approved algorithms
        if (spec.type === KeyType.RSA && spec.size && spec.size < 2048) {
            throw new Error('FIPS mode requires RSA keys >= 2048 bits');
        }
        if (spec.type === KeyType.EC) {
            const approvedCurves = [ECCurve.P256, ECCurve.P384, ECCurve.P521];
            if (spec.curve && !approvedCurves.includes(spec.curve)) {
                throw new Error(`FIPS mode does not allow curve: ${spec.curve}`);
            }
        }
        if (spec.type === KeyType.AES && spec.size && spec.size < 128) {
            throw new Error('FIPS mode requires AES keys >= 128 bits');
        }
    }
    /**
     * Generate symmetric key (C_GenerateKey)
     */
    async generateSymmetricKey(keyId, spec, mechanism) {
        // Build attribute template
        // CK_ATTRIBUTE template[] = {...}
        // C_GenerateKey(session, &mechanism, template, templateSize, &keyHandle)
        const handle = this.handleCounter++;
        const keyMaterial = crypto.randomBytes((spec.size || 256) / 8);
        const obj = {
            handle,
            class: CKO.SECRET_KEY,
            keyType: spec.type === KeyType.AES ? CKK.AES : CKK.GENERIC_SECRET,
            label: spec.label,
            id: Buffer.from(keyId),
            attributes: new Map([
                [CKA.CLASS, CKO.SECRET_KEY],
                [CKA.KEY_TYPE, spec.type === KeyType.AES ? CKK.AES : CKK.GENERIC_SECRET],
                [CKA.LABEL, Buffer.from(spec.label)],
                [CKA.ID, Buffer.from(keyId)],
                [CKA.VALUE, keyMaterial],
                [CKA.VALUE_LEN, (spec.size || 256) / 8],
                [CKA.TOKEN, true],
                [CKA.PRIVATE, true],
                [CKA.SENSITIVE, true],
                [CKA.EXTRACTABLE, spec.extractable],
                [CKA.ENCRYPT, spec.usage.includes(KeyUsage.ENCRYPT)],
                [CKA.DECRYPT, spec.usage.includes(KeyUsage.DECRYPT)],
                [CKA.WRAP, spec.usage.includes(KeyUsage.WRAP)],
                [CKA.UNWRAP, spec.usage.includes(KeyUsage.UNWRAP)],
                [CKA.SIGN, spec.usage.includes(KeyUsage.SIGN)],
                [CKA.VERIFY, spec.usage.includes(KeyUsage.VERIFY)],
            ]),
        };
        this.objectHandles.set(keyId, obj);
    }
    /**
     * Generate key pair (C_GenerateKeyPair)
     */
    async generateKeyPair(keyId, spec, mechanism) {
        // Build public/private key templates
        // C_GenerateKeyPair(session, &mechanism, pubTemplate, pubSize, privTemplate, privSize, &pubHandle, &privHandle)
        const pubHandle = this.handleCounter++;
        const privHandle = this.handleCounter++;
        let publicKey;
        let privateKey;
        if (spec.type === KeyType.RSA) {
            const keyPair = crypto.generateKeyPairSync('rsa', {
                modulusLength: spec.size || 2048,
            });
            publicKey = keyPair.publicKey.export({ type: 'spki', format: 'der' });
            privateKey = keyPair.privateKey.export({ type: 'pkcs8', format: 'der' });
        }
        else {
            // EC
            const curveMap = {
                [ECCurve.P256]: 'prime256v1',
                [ECCurve.P384]: 'secp384r1',
                [ECCurve.P521]: 'secp521r1',
                [ECCurve.SECP256K1]: 'secp256k1',
                [ECCurve.ED25519]: 'ed25519',
            };
            const curve = curveMap[spec.curve || ECCurve.P256];
            if (curve === 'ed25519') {
                const keyPair = crypto.generateKeyPairSync('ed25519');
                publicKey = keyPair.publicKey.export({ type: 'spki', format: 'der' });
                privateKey = keyPair.privateKey.export({ type: 'pkcs8', format: 'der' });
            }
            else {
                const keyPair = crypto.generateKeyPairSync('ec', { namedCurve: curve });
                publicKey = keyPair.publicKey.export({ type: 'spki', format: 'der' });
                privateKey = keyPair.privateKey.export({ type: 'pkcs8', format: 'der' });
            }
        }
        // Store public key object
        const pubObj = {
            handle: pubHandle,
            class: CKO.PUBLIC_KEY,
            keyType: spec.type === KeyType.RSA ? CKK.RSA : CKK.EC,
            label: `${spec.label}-pub`,
            id: Buffer.from(`${keyId}-pub`),
            attributes: new Map([
                [CKA.CLASS, CKO.PUBLIC_KEY],
                [CKA.KEY_TYPE, spec.type === KeyType.RSA ? CKK.RSA : CKK.EC],
                [CKA.LABEL, Buffer.from(`${spec.label}-pub`)],
                [CKA.ID, Buffer.from(`${keyId}-pub`)],
                [CKA.VALUE, publicKey],
                [CKA.TOKEN, true],
                [CKA.VERIFY, spec.usage.includes(KeyUsage.VERIFY)],
                [CKA.ENCRYPT, spec.usage.includes(KeyUsage.ENCRYPT)],
            ]),
        };
        // Store private key object
        const privObj = {
            handle: privHandle,
            class: CKO.PRIVATE_KEY,
            keyType: spec.type === KeyType.RSA ? CKK.RSA : CKK.EC,
            label: `${spec.label}-priv`,
            id: Buffer.from(`${keyId}-priv`),
            attributes: new Map([
                [CKA.CLASS, CKO.PRIVATE_KEY],
                [CKA.KEY_TYPE, spec.type === KeyType.RSA ? CKK.RSA : CKK.EC],
                [CKA.LABEL, Buffer.from(`${spec.label}-priv`)],
                [CKA.ID, Buffer.from(`${keyId}-priv`)],
                [CKA.VALUE, privateKey],
                [CKA.TOKEN, true],
                [CKA.PRIVATE, true],
                [CKA.SENSITIVE, true],
                [CKA.EXTRACTABLE, spec.extractable],
                [CKA.SIGN, spec.usage.includes(KeyUsage.SIGN)],
                [CKA.DECRYPT, spec.usage.includes(KeyUsage.DECRYPT)],
                [CKA.UNWRAP, spec.usage.includes(KeyUsage.UNWRAP)],
            ]),
        };
        this.objectHandles.set(`${keyId}-pub`, pubObj);
        this.objectHandles.set(`${keyId}-priv`, privObj);
        this.objectHandles.set(keyId, privObj); // Map keyId to private key
        return publicKey;
    }
    // ============================================================================
    // Import/Export
    // ============================================================================
    /**
     * Import key (C_CreateObject)
     */
    async importKey(keyMaterial, spec) {
        this.ensureConnected();
        this.validateKeySpec(spec);
        const keyId = spec.id || this.generateKeyId();
        try {
            const handle = this.handleCounter++;
            const obj = {
                handle,
                class: spec.type === KeyType.AES || spec.type === KeyType.HMAC
                    ? CKO.SECRET_KEY
                    : CKO.PRIVATE_KEY,
                label: spec.label,
                id: Buffer.from(keyId),
                attributes: new Map([
                    [CKA.VALUE, keyMaterial],
                    [CKA.LABEL, Buffer.from(spec.label)],
                    [CKA.ID, Buffer.from(keyId)],
                    [CKA.EXTRACTABLE, spec.extractable],
                ]),
            };
            this.objectHandles.set(keyId, obj);
            const keyHandle = {
                id: keyId,
                label: spec.label,
                type: spec.type,
                size: spec.size,
                curve: spec.curve,
                usage: spec.usage,
                extractable: spec.extractable,
                createdAt: new Date(),
                metadata: { imported: true },
            };
            this.keys.set(keyId, keyHandle);
            this.logAudit({
                operation: 'importKey',
                keyId,
                success: true,
            });
            return keyHandle;
        }
        catch (error) {
            const err = error instanceof Error ? error : new Error(String(error));
            this.logAudit({
                operation: 'importKey',
                success: false,
                errorMessage: err.message,
            });
            throw new HSMOperationError('importKey', err.message, this.name, err);
        }
    }
    /**
     * Export public key (C_GetAttributeValue)
     */
    async exportPublicKey(keyHandle) {
        this.ensureConnected();
        const pubObj = this.objectHandles.get(`${keyHandle}-pub`);
        if (!pubObj) {
            throw new HSMKeyNotFoundError(keyHandle, this.name);
        }
        const value = pubObj.attributes.get(CKA.VALUE);
        if (!value || !(value instanceof Buffer)) {
            throw new HSMOperationError('exportPublicKey', 'No public key value', this.name);
        }
        return value;
    }
    /**
     * Get key metadata
     */
    async getKey(keyHandle) {
        this.ensureConnected();
        return this.keys.get(keyHandle) || null;
    }
    /**
     * List keys
     */
    async listKeys(filter) {
        this.ensureConnected();
        let keys = Array.from(this.keys.values());
        if (filter?.type) {
            keys = keys.filter(k => k.type === filter.type);
        }
        if (filter?.label) {
            keys = keys.filter(k => k.label.includes(filter.label));
        }
        return keys;
    }
    // ============================================================================
    // Cryptographic Operations
    // ============================================================================
    /**
     * Sign data (C_SignInit, C_Sign)
     */
    async sign(keyHandle, data, algorithm) {
        this.ensureConnected();
        const obj = this.objectHandles.get(keyHandle) || this.objectHandles.get(`${keyHandle}-priv`);
        if (!obj) {
            throw new HSMKeyNotFoundError(keyHandle, this.name);
        }
        const keyData = this.keys.get(keyHandle);
        if (keyData && !keyData.usage.includes(KeyUsage.SIGN)) {
            throw new HSMPermissionError('Key does not permit signing', this.name);
        }
        try {
            const privateKeyMaterial = obj.attributes.get(CKA.VALUE);
            if (!privateKeyMaterial || !(privateKeyMaterial instanceof Buffer)) {
                throw new Error('No key material available');
            }
            let signature;
            const keyType = keyData?.type;
            if (keyType === KeyType.RSA) {
                const privateKey = crypto.createPrivateKey({
                    key: privateKeyMaterial,
                    format: 'der',
                    type: 'pkcs8',
                });
                signature = crypto.sign('sha256', data, {
                    key: privateKey,
                    padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
                });
            }
            else if (keyType === KeyType.EC) {
                const privateKey = crypto.createPrivateKey({
                    key: privateKeyMaterial,
                    format: 'der',
                    type: 'pkcs8',
                });
                signature = crypto.sign(keyData?.curve === ECCurve.ED25519 ? null : 'sha256', data, privateKey);
            }
            else if (keyType === KeyType.HMAC) {
                const hmac = crypto.createHmac('sha256', privateKeyMaterial);
                signature = hmac.update(data).digest();
            }
            else {
                throw new Error(`Unsupported key type for signing: ${keyType}`);
            }
            this.logAudit({
                operation: 'sign',
                keyId: keyHandle,
                success: true,
                metadata: { algorithm },
            });
            return signature;
        }
        catch (error) {
            const err = error instanceof Error ? error : new Error(String(error));
            this.logAudit({
                operation: 'sign',
                keyId: keyHandle,
                success: false,
                errorMessage: err.message,
            });
            throw new HSMOperationError('sign', err.message, this.name, err);
        }
    }
    /**
     * Verify signature (C_VerifyInit, C_Verify)
     */
    async verify(keyHandle, data, signature, algorithm) {
        this.ensureConnected();
        const obj = this.objectHandles.get(`${keyHandle}-pub`) || this.objectHandles.get(keyHandle);
        if (!obj) {
            throw new HSMKeyNotFoundError(keyHandle, this.name);
        }
        const keyData = this.keys.get(keyHandle);
        if (keyData && !keyData.usage.includes(KeyUsage.VERIFY)) {
            throw new HSMPermissionError('Key does not permit verification', this.name);
        }
        try {
            const keyMaterial = obj.attributes.get(CKA.VALUE);
            if (!keyMaterial || !(keyMaterial instanceof Buffer)) {
                throw new Error('No key material available');
            }
            let result;
            const keyType = keyData?.type;
            if (keyType === KeyType.RSA || keyType === KeyType.EC) {
                const publicKey = crypto.createPublicKey({
                    key: keyMaterial,
                    format: 'der',
                    type: 'spki',
                });
                result = crypto.verify(keyData?.curve === ECCurve.ED25519 ? null : 'sha256', data, keyType === KeyType.RSA
                    ? { key: publicKey, padding: crypto.constants.RSA_PKCS1_PSS_PADDING }
                    : publicKey, signature);
            }
            else if (keyType === KeyType.HMAC) {
                const hmac = crypto.createHmac('sha256', keyMaterial);
                const expected = hmac.update(data).digest();
                result = crypto.timingSafeEqual(signature, expected);
            }
            else {
                throw new Error(`Unsupported key type for verification: ${keyType}`);
            }
            this.logAudit({
                operation: 'verify',
                keyId: keyHandle,
                success: true,
                metadata: { valid: result },
            });
            return result;
        }
        catch (error) {
            const err = error instanceof Error ? error : new Error(String(error));
            this.logAudit({
                operation: 'verify',
                keyId: keyHandle,
                success: false,
                errorMessage: err.message,
            });
            throw new HSMOperationError('verify', err.message, this.name, err);
        }
    }
    /**
     * Encrypt data (C_EncryptInit, C_Encrypt)
     */
    async encrypt(keyHandle, data, options) {
        this.ensureConnected();
        const obj = this.objectHandles.get(keyHandle);
        if (!obj) {
            throw new HSMKeyNotFoundError(keyHandle, this.name);
        }
        const keyData = this.keys.get(keyHandle);
        if (keyData && !keyData.usage.includes(KeyUsage.ENCRYPT)) {
            throw new HSMPermissionError('Key does not permit encryption', this.name);
        }
        try {
            const keyMaterial = obj.attributes.get(CKA.VALUE);
            if (!keyMaterial || !(keyMaterial instanceof Buffer)) {
                throw new Error('No key material available');
            }
            const iv = options?.iv || crypto.randomBytes(12);
            const cipher = crypto.createCipheriv('aes-256-gcm', keyMaterial, iv);
            if (options?.aad) {
                cipher.setAAD(options.aad);
            }
            const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
            const authTag = cipher.getAuthTag();
            const result = Buffer.concat([iv, authTag, encrypted]);
            this.logAudit({
                operation: 'encrypt',
                keyId: keyHandle,
                success: true,
            });
            return result;
        }
        catch (error) {
            const err = error instanceof Error ? error : new Error(String(error));
            this.logAudit({
                operation: 'encrypt',
                keyId: keyHandle,
                success: false,
                errorMessage: err.message,
            });
            throw new HSMOperationError('encrypt', err.message, this.name, err);
        }
    }
    /**
     * Decrypt data (C_DecryptInit, C_Decrypt)
     */
    async decrypt(keyHandle, ciphertext, options) {
        this.ensureConnected();
        const obj = this.objectHandles.get(keyHandle);
        if (!obj) {
            throw new HSMKeyNotFoundError(keyHandle, this.name);
        }
        const keyData = this.keys.get(keyHandle);
        if (keyData && !keyData.usage.includes(KeyUsage.DECRYPT)) {
            throw new HSMPermissionError('Key does not permit decryption', this.name);
        }
        try {
            const keyMaterial = obj.attributes.get(CKA.VALUE);
            if (!keyMaterial || !(keyMaterial instanceof Buffer)) {
                throw new Error('No key material available');
            }
            const iv = ciphertext.subarray(0, 12);
            const authTag = ciphertext.subarray(12, 28);
            const encrypted = ciphertext.subarray(28);
            const decipher = crypto.createDecipheriv('aes-256-gcm', keyMaterial, iv);
            decipher.setAuthTag(authTag);
            if (options?.aad) {
                decipher.setAAD(options.aad);
            }
            const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
            this.logAudit({
                operation: 'decrypt',
                keyId: keyHandle,
                success: true,
            });
            return decrypted;
        }
        catch (error) {
            const err = error instanceof Error ? error : new Error(String(error));
            this.logAudit({
                operation: 'decrypt',
                keyId: keyHandle,
                success: false,
                errorMessage: err.message,
            });
            throw new HSMOperationError('decrypt', err.message, this.name, err);
        }
    }
    /**
     * Wrap key (C_WrapKey)
     */
    async wrapKey(wrappingKeyHandle, keyToWrap, algorithm) {
        this.ensureConnected();
        const wrappingObj = this.objectHandles.get(wrappingKeyHandle);
        const targetObj = this.objectHandles.get(keyToWrap);
        if (!wrappingObj) {
            throw new HSMKeyNotFoundError(wrappingKeyHandle, this.name);
        }
        if (!targetObj) {
            throw new HSMKeyNotFoundError(keyToWrap, this.name);
        }
        const targetKey = this.keys.get(keyToWrap);
        if (targetKey && !targetKey.extractable) {
            throw new HSMOperationError('wrapKey', 'Key is not extractable', this.name);
        }
        try {
            const wrappingKey = wrappingObj.attributes.get(CKA.VALUE);
            const targetKeyMaterial = targetObj.attributes.get(CKA.VALUE);
            if (!wrappingKey || !(wrappingKey instanceof Buffer)) {
                throw new Error('No wrapping key material');
            }
            if (!targetKeyMaterial || !(targetKeyMaterial instanceof Buffer)) {
                throw new Error('No target key material');
            }
            const iv = crypto.randomBytes(12);
            const cipher = crypto.createCipheriv('aes-256-gcm', wrappingKey, iv);
            const encrypted = Buffer.concat([cipher.update(targetKeyMaterial), cipher.final()]);
            const authTag = cipher.getAuthTag();
            const wrapped = Buffer.concat([iv, authTag, encrypted]);
            this.logAudit({
                operation: 'wrapKey',
                keyId: keyToWrap,
                success: true,
            });
            return wrapped;
        }
        catch (error) {
            const err = error instanceof Error ? error : new Error(String(error));
            this.logAudit({
                operation: 'wrapKey',
                success: false,
                errorMessage: err.message,
            });
            throw new HSMOperationError('wrapKey', err.message, this.name, err);
        }
    }
    /**
     * Unwrap key (C_UnwrapKey)
     */
    async unwrapKey(wrappingKeyHandle, wrappedKey, spec, algorithm) {
        this.ensureConnected();
        this.validateKeySpec(spec);
        const wrappingObj = this.objectHandles.get(wrappingKeyHandle);
        if (!wrappingObj) {
            throw new HSMKeyNotFoundError(wrappingKeyHandle, this.name);
        }
        try {
            const wrappingKey = wrappingObj.attributes.get(CKA.VALUE);
            if (!wrappingKey || !(wrappingKey instanceof Buffer)) {
                throw new Error('No wrapping key material');
            }
            const iv = wrappedKey.subarray(0, 12);
            const authTag = wrappedKey.subarray(12, 28);
            const encrypted = wrappedKey.subarray(28);
            const decipher = crypto.createDecipheriv('aes-256-gcm', wrappingKey, iv);
            decipher.setAuthTag(authTag);
            const keyMaterial = Buffer.concat([decipher.update(encrypted), decipher.final()]);
            // Import the unwrapped key
            const importedKey = await this.importKey(keyMaterial, spec);
            this.logAudit({
                operation: 'unwrapKey',
                keyId: importedKey.id,
                success: true,
            });
            return importedKey.id;
        }
        catch (error) {
            const err = error instanceof Error ? error : new Error(String(error));
            this.logAudit({
                operation: 'unwrapKey',
                success: false,
                errorMessage: err.message,
            });
            throw new HSMOperationError('unwrapKey', err.message, this.name, err);
        }
    }
    /**
     * Destroy key (C_DestroyObject)
     */
    async destroyKey(keyHandle) {
        this.ensureConnected();
        const obj = this.objectHandles.get(keyHandle);
        if (!obj) {
            throw new HSMKeyNotFoundError(keyHandle, this.name);
        }
        try {
            // Securely zero key material
            const value = obj.attributes.get(CKA.VALUE);
            if (value instanceof Buffer) {
                crypto.randomFillSync(value);
            }
            this.objectHandles.delete(keyHandle);
            this.objectHandles.delete(`${keyHandle}-pub`);
            this.objectHandles.delete(`${keyHandle}-priv`);
            this.keys.delete(keyHandle);
            this.logAudit({
                operation: 'destroyKey',
                keyId: keyHandle,
                success: true,
            });
        }
        catch (error) {
            const err = error instanceof Error ? error : new Error(String(error));
            this.logAudit({
                operation: 'destroyKey',
                keyId: keyHandle,
                success: false,
                errorMessage: err.message,
            });
            throw new HSMOperationError('destroyKey', err.message, this.name, err);
        }
    }
    // ============================================================================
    // PKCS#11 Specific Methods
    // ============================================================================
    /**
     * Get token info
     */
    getTokenInfo() {
        return this.tokenInfo;
    }
    /**
     * Get slot info
     */
    getSlotInfo(slotId) {
        const id = slotId ?? this.session?.slotId;
        return this.slots.find(s => s.slotId === id);
    }
    /**
     * List available mechanisms
     */
    getMechanisms(slotId) {
        const id = slotId ?? this.session?.slotId ?? 0;
        return this.mechanisms.get(id) || [];
    }
    /**
     * Check if mechanism is supported
     */
    isMechanismSupported(mechanism, slotId) {
        const mechanisms = this.getMechanisms(slotId);
        return mechanisms.some(m => m.mechanism === mechanism);
    }
    /**
     * Generate random bytes using hardware RNG
     */
    async generateRandom(length) {
        this.ensureConnected();
        // C_GenerateRandom(session, randomData, length)
        // For real HSM, this would use hardware RNG
        // In simulation, use crypto.randomBytes
        return crypto.randomBytes(length);
    }
    /**
     * Seed the random number generator
     */
    async seedRandom(seed) {
        this.ensureConnected();
        // C_SeedRandom(session, seed, seedLen)
        // This is a no-op in simulation
        this.logAudit({
            operation: 'seedRandom',
            success: true,
            metadata: { seedLength: seed.length },
        });
    }
    /**
     * Change user PIN
     */
    async changePIN(oldPin, newPin) {
        this.ensureConnected();
        if (!this.session?.loggedIn) {
            throw new HSMPermissionError('Must be logged in to change PIN', this.name);
        }
        // C_SetPIN(session, oldPin, oldPinLen, newPin, newPinLen)
        if (newPin.length < (this.tokenInfo?.minPinLen ?? 4)) {
            throw new Error('New PIN is too short');
        }
        this.logAudit({
            operation: 'changePIN',
            success: true,
        });
    }
}
// ============================================================================
// Factory Function
// ============================================================================
/**
 * Create PKCS#11 wrapper provider
 */
export function createPKCS11Provider(config) {
    return new PKCS11WrapperProvider(config);
}
//# sourceMappingURL=pkcs11-wrapper.js.map