#!/bin/bash -xe
#
# Copyright (c) 2026 Red Hat, Inc.
# Author: Sergio Arroutbi <sarroutb@redhat.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Unit test for pkcs11 public key ID parsing from pkcs11-tool -O output.
# Verifies the ID extraction pipeline handles both old and new output
# formats of pkcs11-tool. The new format (OpenSC >= 0.27.1) shows IDs as
# "DECIMAL (0xHEX)" for small CKA_IDs; the parser must extract the hex
# value from inside the parentheses since pkcs11-tool --read-object --id
# expects hex input.
#
. tests-common-functions

parse_pkcs11_id() {
    echo "$1" | grep -i 'Public' -A10 | grep 'ID:' \
        | head -1 | awk -F 'ID:' '{
        val = $2
        if (match(val, /\(0x[^)]+\)/)) {
            val = substr(val, RSTART+3, RLENGTH-4)
            print val
        } else {
            gsub(/^[[:space:]]+|[[:space:]]+$/, "", val)
            print val
        }
    }'
}

# New pkcs11-tool format: decimal with hex in parentheses
# Must extract hex "03", not decimal "3"
PKCS11_OUTPUT_NEW_FORMAT="Public Key Object; RSA  2048 bits
  label:      KEY MAN pubkey
  ID:         3 (0x03)
  Usage:      encrypt, wrap
  Access:     none"

id=$(parse_pkcs11_id "${PKCS11_OUTPUT_NEW_FORMAT}")
test "${id}" == "03" || error "New format: expected '03', got '${id}'"

# Old pkcs11-tool format: plain hex without annotation
PKCS11_OUTPUT_OLD_FORMAT="Public Key Object; RSA  2048 bits
  label:      KEY MAN pubkey
  ID:         03
  Usage:      encrypt, wrap
  Access:     none"

id=$(parse_pkcs11_id "${PKCS11_OUTPUT_OLD_FORMAT}")
test "${id}" == "03" || error "Old format: expected '03', got '${id}'"

# Decimal differs from hex: decimal 10 is hex 0a
# Must extract "0a", not "10"
PKCS11_OUTPUT_DEC_HEX_DIFFER="Public Key Object; RSA  2048 bits
  label:      KEY MAN pubkey
  ID:         10 (0x0a)
  Usage:      encrypt, wrap
  Access:     none"

id=$(parse_pkcs11_id "${PKCS11_OUTPUT_DEC_HEX_DIFFER}")
test "${id}" == "0a" || error "Decimal/hex differ: expected '0a', got '${id}'"

# Two-byte hex ID
PKCS11_OUTPUT_TWO_BYTE="Public Key Object; RSA  4096 bits
  label:      KEY MAN pubkey
  ID:         65281 (0xff01)
  Usage:      encrypt, wrap
  Access:     none"

id=$(parse_pkcs11_id "${PKCS11_OUTPUT_TWO_BYTE}")
test "${id}" == "ff01" || error "Two-byte hex: expected 'ff01', got '${id}'"

# ID where decimal == hex (single digit, 0-9)
PKCS11_OUTPUT_SINGLE_DIGIT="Public Key Object; RSA  2048 bits
  label:      KEY MAN pubkey
  ID:         1 (0x01)
  Usage:      encrypt, wrap
  Access:     none"

id=$(parse_pkcs11_id "${PKCS11_OUTPUT_SINGLE_DIGIT}")
test "${id}" == "01" || error "Single digit: expected '01', got '${id}'"

# Multiple objects: should pick the first Public Key ID hex value
PKCS11_OUTPUT_MULTIPLE="Certificate Object; type = X.509 cert
  label:      Certificate for Key Management
  ID:         99
Public Key Object; RSA  2048 bits
  label:      KEY MAN pubkey
  ID:         42 (0x2a)
  Usage:      encrypt, wrap
  Access:     none"

id=$(parse_pkcs11_id "${PKCS11_OUTPUT_MULTIPLE}")
test "${id}" == "2a" || error "Multiple objects: expected '2a', got '${id}'"

# Old format with multi-byte hex (no parentheses)
PKCS11_OUTPUT_OLD_MULTI="Public Key Object; RSA  2048 bits
  label:      KEY MAN pubkey
  ID:         ff01
  Usage:      encrypt, wrap
  Access:     none"

id=$(parse_pkcs11_id "${PKCS11_OUTPUT_OLD_MULTI}")
test "${id}" == "ff01" || error "Old multi-byte: expected 'ff01', got '${id}'"
