#!/bin/bash

# Script de conversion d'extension de certificat vers plusieurs formats
# Auteur : Cbillet
# Date : 10/11/2024
# Version : 1.0 (conversion optimisée et prise en charge des alias de format)

# Liste des extensions de sortie valides
VALID_EXTENSIONS=("pem" "der" "cer" "crt" "cert" "p12" "pfx" "p7b")

# Codes de couleur pour une sortie améliorée
GREEN='\e[1;32m'
RED='\e[1;31m'
YELLOW='\e[1;33m'
CYAN='\e[1;36m'
RESET='\e[0m'

# Affichage de l'aide
Help() {
    echo -e "\n${CYAN}Script de conversion d'extension de certificat vers plusieurs formats${RESET}"
    echo -e "\n${GREEN}USAGE :${RESET}"
    echo -e "  $0 -i \e[3m<input_file>\e[0m -e \e[3m<extensions_output>\e[0m [-o \e[3m<output_prefix>\e[0m] [-k \e[3m<private_key_file>\e[0m]"
    echo -e "\n${GREEN}OPTIONS :${RESET}"
    echo -e "  ${YELLOW}-i, --input${RESET} \e[3m<input_file>\e[0m               Fichier de certificat d'entrée (obligatoire)"
    echo -e "  ${YELLOW}-e, --extensions${RESET} \e[3m<extensions_output>\e[0m   Extensions de sortie souhaitées, séparées par des virgules (obligatoire)"
    echo -e "                                          Extensions valides : ${CYAN}${VALID_EXTENSIONS[*]}${RESET}"
    echo -e "  ${YELLOW}-o, --output-prefix${RESET} \e[3m<output_prefix>\e[0m    Préfixe pour les fichiers de sortie (optionnel)"
    echo -e "                                          Par défaut : nom de fichier d'entrée sans extension"
    echo -e "  ${YELLOW}-k, --key${RESET} \e[3m<private_key_file>\e[0m          Fichier de clé privée requis pour la conversion en .p12 ou .pfx"
    echo -e "  ${YELLOW}-h, --help${RESET}                              Affiche cette aide\n"
    echo -e "\n${GREEN}LIMITATIONS :${RESET}"
    echo -e "  - Conversion en .p7b limitée aux chaînes de certificats sans clé privée."
    echo -e "  - Certaines conversions de .der et .p7b vers d'autres formats peuvent ne pas être supportées."
}

# Vérification si une extension est valide
is_valid_extension() {
    local ext="$1"
    for valid_ext in "${VALID_EXTENSIONS[@]}"; do
        if [[ "$ext" == "$valid_ext" ]]; then
            return 0
        fi
    done
    return 1
}

# Fonction de conversion de certificat
convert_cert() {
    local input_file="$1"
    local output_file="$2"
    local input_ext="${input_file##*.}"
    local output_ext="${output_file##*.}"

    case "$input_ext" in
        "crt"|"cer"|"cert"|"pem")
            case "$output_ext" in
                "pem"|"crt"|"cer"|"cert")
                    openssl x509 -in "$input_file" -out "$output_file" 2>/dev/null
                    ;;
                "der")
                    openssl x509 -in "$input_file" -outform der -out "$output_file" 2>/dev/null
                    ;;
                "p12"|"pfx")
                    if [[ -z "$PRIVATE_KEY_FILE" ]]; then
                        echo -e "${RED}Erreur : La conversion en .p12 ou .pfx nécessite un fichier de clé privée spécifié avec -k.${RESET}"
                        exit 1
                    fi
                    openssl pkcs12 -export -in "$input_file" -inkey "$PRIVATE_KEY_FILE" -out "$output_file" 2>/dev/null
                    ;;
                "p7b")
                    echo -e "${YELLOW}Info : Conversion en .p7b est limitée aux chaînes de certificats sans clé privée.${RESET}"
                    openssl crl2pkcs7 -nocrl -certfile "$input_file" -out "$output_file" -outform DER 2>/dev/null
                    ;;
                *)
                    echo -e "${RED}Erreur : Format de sortie non supporté ($output_ext)${RESET}"
                    exit 1
                    ;;
            esac
            ;;
        "der")
            case "$output_ext" in
                "pem"|"crt"|"cer"|"cert")
                    openssl x509 -inform der -in "$input_file" -out "$output_file" 2>/dev/null
                    ;;
                "p12"|"pfx")
                    if [[ -z "$PRIVATE_KEY_FILE" ]]; then
                        echo -e "${RED}Erreur : La conversion en .p12 ou .pfx nécessite un fichier de clé privée spécifié avec -k.${RESET}"
                        exit 1
                    fi
                    openssl pkcs12 -export -in "$input_file" -inkey "$PRIVATE_KEY_FILE" -out "$output_file" 2>/dev/null
                    ;;
                "p7b")
                    echo -e "${YELLOW}Info : Conversion en .p7b est limitée aux chaînes de certificats sans clé privée.${RESET}"
                    openssl crl2pkcs7 -nocrl -certfile "$input_file" -out "$output_file" -outform DER 2>/dev/null
                    ;;
                *)
                    echo -e "${RED}Erreur : Conversion non supportée pour ce format d'entrée ($input_ext)${RESET}"
                    exit 1
                    ;;
            esac
            ;;
        "p12"|"pfx")
            case "$output_ext" in
                "pem")
                    openssl pkcs12 -in "$input_file" -out "$output_file" -nodes 2>/dev/null
                    ;;
                "der"|"cer"|"crt"|"cert")
                    openssl pkcs12 -in "$input_file" -out "$output_file" -outform der 2>/dev/null
                    ;;
                "p7b")
                    echo -e "${YELLOW}Info : Extraction des certificats uniquement pour le format .p7b sans clé privée.${RESET}"
                    openssl pkcs12 -in "$input_file" -out "$output_file" -certfile "$input_file" -outform DER 2>/dev/null
                    ;;
                *)
                    echo -e "${RED}Erreur : Conversion non supportée pour ce format d'entrée ($input_ext)${RESET}"
                    exit 1
                    ;;
            esac
            ;;
        "p7b")
            case "$output_ext" in
                "pem")
                    openssl pkcs7 -in "$input_file" -print_certs -out "$output_file" 2>/dev/null
                    ;;
                *)
                    echo -e "${RED}Erreur : Format de sortie non supporté ($output_ext)${RESET}"
                    exit 1
                    ;;
            esac
            ;;
        *)
            echo -e "${RED}Erreur : Format d'entrée non supporté ($input_ext)${RESET}"
            exit 1
            ;;
    esac

    # Vérification de succès
    if [[ -f "$output_file" ]]; then
        echo -e "${GREEN}Conversion réussie : $output_file${RESET}"
    else
        echo -e "${RED}Erreur : La conversion a échoué.${RESET}"
        exit 1
    fi
}

# Gestion des options
while getopts ":i:e:o:k:h" opt; do
    case "$opt" in
        i) INPUT_FILE="$OPTARG" ;;
        e) EXTENSIONS_OUTPUT="$OPTARG" ;;
        o) OUTPUT_PREFIX="$OPTARG" ;;
        k) PRIVATE_KEY_FILE="$OPTARG" ;;
        h) Help; exit 0 ;;
        \?) echo -e "${RED}Option invalide : -$OPTARG${RESET}"; Help; exit 1 ;;
        :) echo -e "${RED}L'option -$OPTARG requiert un argument.${RESET}"; Help; exit 1 ;;
    esac
done

# Validation des paramètres requis
if [[ -z "$INPUT_FILE" || -z "$EXTENSIONS_OUTPUT" ]]; then
    echo -e "${RED}Erreur : Les options --input et --extensions sont obligatoires.${RESET}"
    Help
    exit 1
fi

# Si aucun préfixe de sortie n'est spécifié, utiliser le nom de fichier d'entrée sans extension
if [[ -z "$OUTPUT_PREFIX" ]]; then
    OUTPUT_PREFIX="${INPUT_FILE%.*}"
fi

# Conversion pour chaque extension demandée
IFS=',' read -ra OUTPUT_EXTENSIONS <<< "$EXTENSIONS_OUTPUT"
for ext in "${OUTPUT_EXTENSIONS[@]}"; do
    # Vérification de l'extension
    if ! is_valid_extension "$ext"; then
        echo -e "${RED}Erreur : L'extension de sortie spécifiée ($ext) n'est pas valide.${RESET}"
        echo -e "${CYAN}Extensions valides : ${VALID_EXTENSIONS[*]}${RESET}"
        exit 1
    fi
    
    # Éviter les conversions redondantes de .pfx vers .p12 ou inversement
    if [[ "$input_ext" == "pfx" && "$ext" == "p12" ]] || [[ "$input_ext" == "p12" && "$ext" == "pfx" ]]; then
        echo -e "${YELLOW}Info : Conversion .pfx vers .p12 (ou inverse) est redondante et sera ignorée.${RESET}"
        continue
    fi

    # Définir le nom de fichier de sortie
    output_file="${OUTPUT_PREFIX}.${ext}"
    
    # Appeler la fonction de conversion
    convert_cert "$INPUT_FILE" "$output_file"
done
