#!/bin/bash
# License: lgpl v2

main(){
  public_name="Auto-Generate SSL"
  system_name=generate_ssl
  version=0.3.1

  local entropy="/dev/random"

  local mode="rsa"
  local country=
  local province=
  local city=
  local organization=
  local unit=
  local domain=
  local bits=
  local short_name=
  local subject=
  local subject_prefix=
  local days=1095 # default to 3 years
  local certificate_type=self-signed
  local encrypt=nodes
  local destination=
  local utf8=
  local digest=sha256
  local key=
  local serial=

  while [[ $count -lt $main_size ]] ; do
    i=${main_input[$count]}

    if [[ $grab_next == "" ]] ; then
      if [[ $i == "-h" || $i == "--help" ]] ; then
        do_help=yes
      elif [[ $i == "+n" || $i == "++no_color" ]] ; then
        do_color=none
      elif [[ $i == "+l" || $i == "++light" ]] ; then
        do_color=light
      elif [[ $i == "+v" || $i == "++version" ]] ; then
        echo $version
        return
      elif [[ $i == "-m" || $i == "--mode" ]] ; then
        grab_next=mode
      elif [[ $i == "-C" || $i == "--country" ]] ; then
        grab_next=country
      elif [[ $i == "-o" || $i == "--organization" ]] ; then
        grab_next=organization
      elif [[ $i == "-u" || $i == "--unit" ]] ; then
        grab_next=unit
      elif [[ $i == "-d" || $i == "--domain" ]] ; then
        grab_next=domain
      elif [[ $i == "-p" || $i == "--province" ]] ; then
        grab_next=province
      elif [[ $i == "-c" || $i == "--city" ]] ; then
        grab_next=city
      elif [[ $i == "-b" || $i == "--bits" ]] ; then
        grab_next=bits
      elif [[ $i == "-D" || $i == "--days" ]] ; then
        grab_next=days
      elif [[ $i == "-t" || $i == "--certificate_type" ]] ; then
        grab_next=certificate_type
      elif [[ $i == "-e" || $i == "--encrypt" ]] ; then
        grab_next=encrypt
      elif [[ $i == "-E" || $i == "--entropy" ]] ; then
        grab_next=entropy
      elif [[ $i == "-a" || $i == "--auto" ]] ; then
        auto=yes
      elif [[ $i == "-D" || $i == "--destination" ]] ; then
        grab_next=destination
      elif [[ $i == "-U" || $i == "--utf8" ]] ; then
        utf8="-utf8"
      elif [[ $i == "+d" || $i == "++digest" ]] ; then
        grab_next=digest
      elif [[ $i == "-k" || $i == "--key" ]] ; then
        grab_next=key
      elif [[ $i == "-s" || $i == "--serial" ]] ; then
        grab_next=serial
      fi
    else
      if [[ $grab_next == "mode" ]] ; then
        mode=$i

        if [[ $bits == "" ]] ; then
          if [[ $mode == "dsa" ]] ; then
            bits=1024
          else
            bits=2048
          fi
        fi
      elif [[ $grab_next == "country" ]] ; then
        country=$(echo $i | sed -e 's|"||g')
      elif [[ $grab_next == "organization" ]] ; then
        organization=$(echo $i | sed -e 's|"||g')
      elif [[ $grab_next == "unit" ]] ; then
        unit=$(echo $i | sed -e 's|"||g')
      elif [[ $grab_next == "domain" ]] ; then
        domain=$(echo $i | sed -e 's|"||g')
      elif [[ $grab_next == "province" ]] ; then
        province=$(echo $i | sed -e 's|"||g')
      elif [[ $grab_next == "city" ]] ; then
        city=$(echo $i | sed -e 's|"||g')
      elif [[ $grab_next == "bits" ]] ; then
        bits=$i
      elif [[ $grab_next == "days" ]] ; then
        days=$i
      elif [[ $grab_next == "certificate_type" ]] ; then
        certificate_type=$i
      elif [[ $grab_next == "encrypt" ]] ; then
        encrypt=$i
      elif [[ $grab_next == "entropy" ]] ; then
        entropy=$i
      elif [[ $grab_next == "destination" ]] ; then
        destination=$(echo $i | sed -e 's|/*$|/|')
      elif [[ $grab_next == "digest" ]] ; then
        if [[ $i == "md5" || $i == "sha" || $i == "sha1" || $i == "sha224" || $i == "sha256" || $i == "sha384" || $i == "sha512" || $i == "md2" || $i == "mdc2" || $i == "md4" || $i == "whirlpool" || $i == "ripemd160" ]] ; then
          digest=$i
        fi
      elif [[ $grab_next == "key" ]] ; then
        if [[ $i == "des" || $i == "des3" || $i == "idea" || $i == "seed" || $i == "aes128" || $i == "aes196" || $i == "aes256" || $i == "camellia128" || $i == "camellia196" || $i == "camellia256" ]] ; then
          key="-$i"
        fi
      elif [[ $grab_next == "serial" ]] ; then
        serial="-set_serial $i"
      fi

      grab_next=
    fi

    let count=$count+1
  done

  standard_handle_colors

  if [[ $do_help != "" ]] ; then
    show_help
    return
  fi

  if [[ $destination != "" && ! -d $destination ]] ; then
    standard_error "The destination '$c_notice$destination$c_error' is not a valid directory"
    cleanup_main
    exit -1
  fi

  if [[ $domain == "" ]] ; then
    short_name=server
  else
    short_name=$(echo $domain | grep -s -o "^[[:alnum:]]*\>")
  fi

  encrypt="-$encrypt"

  if [[ $mode == "rsa" ]] ; then
    # Generate RSA
    openssl genrsa -rand $entropy -out $destination$short_name.private $bits $key

    if [[ $? -ne 0 ]] ; then
      standard_error "Failed to execute: ${c_notice}openssl genrsa -rand $entropy -out $destination$short_name.private $bits $key"
      cleanup_main
      exit -1
    fi
  elif [[ $mode == "dsa" ]] ; then
    # Generate DSA
    openssl dsaparam -rand $entropy -noout -out $destination$short_name.private -genkey $bits $key

    if [[ $? -ne 0 ]] ; then
      standard_error "Failed to execute: ${c_notice}openssl dsaparam -rand $entropy -noout -out $destination$short_name.private -genkey $bits $key"
      cleanup_main
      exit -1
    fi
  else
    standard_error "Invalid mode, can only be '${c_notice}rsa${c_error}' or '${c_notice}dsa${c_error}'"
    cleanup_main
    exit -1
  fi

  # Populate subject string
  if [[ $country != "" ]] ; then
    subject="/C=$country"
  fi

  if [[ $domain != "" ]] ; then
    subject="$subject/CN=$domain"
  fi

  if [[ $province != "" ]] ; then
    subject="$subject/ST=$province"
  fi

  if [[ $city != "" ]] ; then
    subject="$subject/L=$city"
  fi

  if [[ $organization != "" ]] ; then
    subject="$subject/O=$organization"
  fi

  if [[ $unit != "" ]] ; then
    subject="$subject/OU=$unit"
  fi

  if [[ $subject != "" ]] ; then
    subject="-subj $subject"
    subject_prefix="-subj"
  fi

  if [[ $certificate_type == "request" ]] ; then
    # Generate Certificate Request
    openssl req -new -key $destination$short_name.private -out $destination$short_name.request $subject_prefix "$subject" $utf8

    if [[ $? -ne 0 ]] ; then
      standard_error "Failed to execute: ${c_notice}openssl req -new -key $destination$short_name.private -out $destination$short_name.request $subject_prefix \"$subject\" $utf8"
      cleanup_main
      exit -1
    fi
  elif [[ $certificate_type == "self-signed" ]] ; then
    # Generate Self-Signed Certificate
    openssl req -new -x509 $encrypt -key $destination$short_name.private -out $destination$short_name.certificate -sha1 -days $days -nameopt RFC2253 $subject $utf8 $serial

    if [[ $? -ne 0 ]] ; then
      standard_error "Failed to execute: ${c_notice}openssl req -new -x509 $encrypt -key $destination$short_name.private -out $destination$short_name.certificate -sha1 -days $days -nameopt RFC2253 $subject $utf8 $serial"
      cleanup_main
      exit -1
    fi

    # Combine the public & private keys
    cat $destination$short_name.certificate $destination$short_name.private > $destination$short_name.combined

    if [[ $? -ne 0 ]] ; then
      standard_error "Failed to execute: ${c_notice}cat $destination$short_name.certificate $destination$short_name.private > $destination$short_name.combined"
      cleanup_main
      exit -1
    fi
  else
    standard_error "Invalid certificate type, can only be '${c_notice}self-signed${c_reset}' or '${c_notice}request${c_reset}'"
    cleanup_main
    exit -1
  fi
}

show_help(){
  standard_help_title
  echo -e "$c_highlight$system_name$c_reset $c_notice[${c_reset}options$c_notice]$c_reset"
  echo
  standard_help_options
  echo -e " -${c_important}m${c_reset}, --${c_important}mode${c_reset}              Key mode: rsa or dsa"
  echo -e " -${c_important}c${c_reset}, --${c_important}country${c_reset}           2-Letter country code"
  echo -e " -${c_important}o${c_reset}, --${c_important}organization${c_reset}      Organization to use"
  echo -e " -${c_important}u${c_reset}, --${c_important}unit${c_reset}              Organization unit to use"
  echo -e " -${c_important}d${c_reset}, --${c_important}domain${c_reset}            Domain/Url in which SSL is for"
  echo -e " -${c_important}p${c_reset}, --${c_important}province${c_reset}          State/Province in which SSL is for"
  echo -e " -${c_important}b${c_reset}, --${c_important}bits${c_reset}              Encryption bits, suggested: 1024 or 2048"
  echo -e " -${c_important}D${c_reset}, --${c_important}days${c_reset}              Number of days the certificate is valid for"
  echo -e " -${c_important}t${c_reset}, --${c_important}certificate_type${c_reset}  Either: self-signed or request"
  echo -e " -${c_important}e${c_reset}, --${c_important}encrypt${c_reset}           Encryption mode: nodes, 3des, etc.."
  echo -e " -${c_important}E${c_reset}, --${c_important}entropy${c_reset}           Entropy source: /dev/random, /dev/urandom, etc.."
  echo -e " -${c_important}D${c_reset}, --${c_important}destination${c_reset}       Specify a directory to place generated files"
  echo -e " -${c_important}U${c_reset}, --${c_important}utf8${c_reset}              Use utf8 instead of the default ascii"
  echo -e " -${c_important}k${c_reset}, --${c_important}key${c_reset}               Encrypt the key, choices: des, des3, idea, seed, aes128, aes192, aes256, camellia128, camellia196, camellia256"
  echo -e " -${c_important}s${c_reset}, --${c_important}serial${c_reset}            Set the serial used on a certificate"
  echo -e " +${c_important}d${c_reset}, ++${c_important}digest${c_reset}            Digest to use, choices: md5, sha, sha1, sha224, sha256, sha512, md2, mdc2, md4, whirlpool, ripemd160"
  echo
}

cleanup_main(){
  standard_unset

  unset show_help
  unset main
  unset cleanup_main
}

OLD_PATH=$PATH
PATH=/tkis//tools/lib/scripts/turtle_kevux/:$PATH
source $(type -p turtle_kevux_scripts-standard)
PATH=$OLD_PATH
unset OLD_PATH

# populate main_input variable
main_input=
main_size=$#
c1=0
c2=

while [[ $c1 -lt $main_size ]] ; do
  let c2=$c1+1
  main_input[$c1]=${!c2}
  let c1=$c1+1
done

unset c1 c2

# execute the program
standard_main_execute=main
standard_main
cleanup_main
unset main_input main_size
