#!/bin/bash
set +x
source /opt/huawei/snas/script/inspect_mml/CheckItems

CurInspectNum="274"
CurInspectFun=`GetInspectType $CurInspectNum`
RESULTFILE="/tmp/tmpResult${CurInspectFun}"
>$RESULTFILE

isPass=0
AllNodeNeedPemList="/opt/huawei/snas/etc/sslcert.pem /opt/huawei/snas/etc/sslca.cer /opt/huawei/deploy/etc/Equipment_Root_CA.der /opt/huawei/deploy/etc/IT_Product_CA.cer /etc/softcert/HuaweiRootCA.der /opt/huawei/deploy/etc/cluster_ca.cer /opt/huawei/deploy/etc/cluster_cert.pem /opt/huawei/deploy/etc/toolkit_dep_ca.cer /opt/Runtime/tomcat7/conf/server.pem /opt/Runtime/tomcat7/conf/server.cer"
MayBeNonexistPemlist="/etc/ssl/private/server_cert.pem /opt/huawei/snas/etc/cert/alarm/cacert.pem /opt/huawei/snas/etc/cert/password/cacert.pem /opt/huawei/snas/etc/cert/emui/cacert.pem /etc/rsyslog-key/client_cert.pem /etc/rsyslog-key/ca.pem /opt/deviceManager/apache/conf/ca.crt"
viidPemList="/opt/huawei/viid/config/server/server.pem /opt/huawei/viid/config/server/server.cer"
DomainZeroPemList="/opt/huawei/deploy/etc/toolkit_dep_cert.pem /opt/deviceManager/apache/conf/cert_en.pem"
DominkeyStorelist="/opt/Runtime/tomcat7/cert/ToolKitDeploy.keystore /opt/Runtime/tomcat7/cert/IT_CA.keystore /opt/Runtime/tomcat7/conf/server.keystore" 
S3keyStorelist="/opt/obs/service/osc/etc/keystore /opt/obs/service/poe/etc/keystore /opt/obs/service/dcm/etc/keystore"
S3PemList="/var/uds/user/data_upf/server.crt"

#NoReplaceCertiList="/opt/product/deploy/etc/Equipment_Root_CA.der /opt/product/deploy/etc/IT_Product_CA.cer /etc/softcert/HuaweiRootCA.der /opt/product/deploy/etc/cluster_ca.cer /opt/product/deploy/etc/cluster_cert.pem /opt/product/deploy/etc/toolkit_dep_cert.pem /opt/deviceManager/apache/conf/cert_en.pem /opt/Runtime/tomcat7/cert/IT_CA.keystore"
function set_ifs
{
    IFS_OLD=$IFS
    IFS=$'\n'
}

function restore_ifs
{
    IFS=$IFS_OLD
}

#判断节点是否是UDS/S3节点,是的话,返回0,不是,返回1
function CheckNodeServiceType()
{
    local cfgfile="/opt/product/snas/etc/snas.ini"
    local UDS_Type="80"
    local DFS_Type="48"
    local DFS_ServiceType="1"
    if [ ! -f ${cfgfile} ];then
        echo "[ERR]INFO:The file ${cfgfile} does not exist.Cannot tell if the node belongs to the 0 subdomain." >>$RESULTFILE 2>&1
        echo "NULL"
        return
    fi
    local ProductType=$( grep productType ${cfgfile} |awk -F= '{print $2}' )
    if [ "X" == "X${ProductType}" ];then
        echo "[ERR]INFO:Get ProductType from ${cfgfile} failed." >>$RESULTFILE 2>&1
        echo "NULL"
        return
    fi
    if [ "X${UDS_Type}" == "X${ProductType}" ];then
        echo 0
        return
    fi
    if [ "X${DFS_Type}" == "X${ProductType}" ];then
        local nodeServiceType=$( grep node_service_type ${cfgfile} | awk -F"=" '{print $2}' )
        if [ "X" == "X${nodeServiceType}" ];then
            echo "[ERR]INFO:Get nodeServiceType from ${cfgfile} failed." >>$RESULTFILE 2>&1
            echo "NULL"
            return
        fi
        if [ "X${DFS_ServiceType}" != "X${nodeServiceType}" ];then
            echo 0
            return
        fi
    fi

   echo 1
}

function GetDomain()
{
    local cfgfile="/opt/product/snas/etc/cm.ini"
    if [ ! -f ${cfgfile} ];then
        echo "[ERR]INFO:The file ${cfgfile} does not exist.Cannot tell if the node belongs to the 0 subdomain" >>$RESULTFILE 2>&1
        echo "NULL"
        return
    fi
    local SubDomain=$( grep SubDomain ${cfgfile} | awk -F"=" '{print $2}' )
    if [ "X" == "X${SubDomain}" ];then
        echo "[ERR]INFO:Get  SubDomain from ${cfgfile} failed." >>$RESULTFILE 2>&1
        echo "NULL"
        return
    fi
    echo "${SubDomain}"
}

# 有些证书需要申请或者需要某些特性才能使用
function getMayBeNonexistPem()
{
    local iRet=""
    local iRet1=""
    local DeadLine=""
    local SHAkey=""

    for item in ${MayBeNonexistPemlist}
    do
        if [ ! -f ${item} ];then
            # 直接不用管。退出即可
            continue
        fi
        DeadLine=$( openssl x509 -enddate -noout -in ${item} | awk -F"=" '{print $2}' )
        iRet=$?
        if [ 0 -ne ${iRet} ];then
             DeadLine="NA"
             echo "[ERR]INFO:Get ${item} deadline failed"  >>$RESULTFILE 2>&1
             continue
        fi
        if [ "X" == "X${DeadLine}" ];then
            DeadLine="NA"
            continue
        fi
        SHAkey=$( openssl x509 -fingerprint -noout -in ${item} | awk -F"=" '{print $2}' )
        iRet1=$?
        if [ 0 -ne ${iRet1} ];then
            SHAkey="NA"
            continue
        fi
        if [ "X" == "X${SHAkey}" ];then
            SHAkey="NA"
            continue
        fi
        echo "name=${item};DeadLine=${DeadLine};Key=${SHAkey}"
    done

    # 针对viid视频语义这个特性，如果部署时候没有开启，后续就不会再开启咯
    viidSwitch=$( cat /opt/huawei/snas/etc/snas.ini |tr \\n ] |grep -Po '(?<=[[]'SERVICE'[]]).*' |tr ] \\n |grep -Po '(?<=^'viid'=).*' |awk 'NR==1{print}' )
    if [ X"${viidSwitch}" != X"1" ]; then
        LOG "[$FUNCNAME][$LINENO]viid is not in use.no need to check viid certificate."
        return
    fi

    for item in ${viidPemList}
    do
        if [ ! -f ${item} ];then
            # 直接不用管。退出即可
            continue
        fi
        DeadLine=$( openssl x509 -enddate -noout -in ${item} | awk -F"=" '{print $2}' )
        iRet=$?
        if [ 0 -ne ${iRet} ];then
             DeadLine="NA"
             echo "[ERR]INFO:Get ${item} deadline failed"  >>$RESULTFILE 2>&1
             continue
        fi
        if [ "X" == "X${DeadLine}" ];then
            DeadLine="NA"
            continue
        fi
        SHAkey=$( openssl x509 -fingerprint -noout -in ${item} | awk -F"=" '{print $2}' )
        iRet1=$?
        if [ 0 -ne ${iRet1} ];then
            SHAkey="NA"
            continue
        fi
        if [ "X" == "X${SHAkey}" ];then
            SHAkey="NA"
            continue
        fi
        echo "name=${item};DeadLine=${DeadLine};Key=${SHAkey}"
    done

    return
}

#所有类型节点都需要而且都存在的证书
function getALLPem()
{
    local iRet=""
    local iRet1=""

    for item in ${AllNodeNeedPemList}
    do
        if [ ! -f ${item} ];then
            echo "name=${item};DeadLine=NA;Key=NA"
            continue
        fi
        local DeadLine=$( openssl x509 -enddate -noout -in ${item} | awk -F"=" '{print $2}' )
        iRet=$?
        if [ 0 -ne ${iRet} ];then
             DeadLine="NA"
             echo "[ERR]INFO:Get ${item} deadline failed"  >>$RESULTFILE 2>&1
             continue
        fi
        if [ "X" == "X${DeadLine}" ];then
            DeadLine="NA"
            continue
        fi
        local SHAkey=$( openssl x509 -fingerprint -noout -in ${item} | awk -F"=" '{print $2}' )
        iRet1=$?
        if [ 0 -ne ${iRet1} ];then
            SHAkey="NA"
            continue
        fi
        if [ "X" == "X${SHAkey}" ];then
            SHAkey="NA"
            continue
        fi
        echo "name=${item};DeadLine=${DeadLine};Key=${SHAkey}"
    done

}
#所有类型节点都需要检查的证书
function getS3Pem()
{
    local iRet=""
    local iRet1=""

    for item in ${S3PemList}
    do
        if [ ! -f ${item} ];then
            echo "name=${item};DeadLine=NA;Key=NA"
            continue
        fi
        local DeadLine=$( openssl x509 -enddate -noout -in ${item} | awk -F"=" '{print $2}' )
        iRet=$?
        if [ 0 -ne ${iRet} ];then
             DeadLine="NA"
             echo "get ${item} deadline failed"
             continue
        fi
        if [ "X" == "X${DeadLine}" ];then
            DeadLine="NA"
            continue
        fi
        local SHAkey=$( openssl x509 -fingerprint -noout -in ${item} | awk -F"=" '{print $2}' )
        iRet1=$?
        if [ 0 -ne ${iRet1} ];then
            SHAkey="NA"
            continue
        fi
        if [ "X" == "X${SHAkey}" ];then
            SHAkey="NA"
            continue
        fi
        echo "name=${item};DeadLine=${DeadLine};Key=${SHAkey}"
    done

}

#只需要检查0号子域的证书
function getZeroPemCerti()
{

    local iRet=""
    local iRet1=""

    for item in ${DomainZeroPemList}
    do

        if [ ! -f ${item} ];then
            echo "name=${item};DeadLine=NA;Key=NA"
            continue
        fi
        local DeadLine=$( openssl x509 -enddate -noout -in ${item} | awk -F"=" '{print $2}' )
        iRet=$?
        if [ 0 -ne ${iRet} ];then
             DeadLine="NA"
            continue
        fi
        if [ "X" == "X${DeadLine}" ];then
            DeadLine="NA"
            continue
        fi
        local SHAkey=$( openssl x509 -fingerprint -noout -in ${item} | awk -F"=" '{print $2}' )
        iRet1=$?
        if [ 0 -ne ${iRet1} ];then
             SHAkey="NA"
            continue
        fi
        if [ "X" == "X${SHAkey}" ];then
            SHAkey="NA"
            continue
        fi
        echo "name=${item};DeadLine=${DeadLine};Key=${SHAkey}"
    done

}

function getTimeZoneDiffSeconds()
{
    local timeSeconds=$1
    local curTimeZone="$(date +%z)"
    local curTimeZoneSign="${curTimeZone:0:1}"
    local curTimeZoneHour="${curTimeZone:1:2}"
    local curTimeZoneMin="${curTimeZone:3:2}"
    local diffSeconds=$(echo "${curTimeZoneHour} * 3600 + ${curTimeZoneMin} * 60" | bc)
    if [ "X${curTimeZoneSign}" == "X+" ];then
        timeSeconds=$(($timeSeconds - $diffSeconds))
    else
        timeSeconds=$(($timeSeconds + $diffSeconds))
    fi
    echo "${timeSeconds}"
}

function getVerArrayIndex()
{
    rec=$1

    local index=0

    for item in ${checkVerArray[@]}
    do
        if [ "$rec" = "$item" ]; then
            break
        else
            index=$((index+1))
        fi
    done

    echo $index
}

#检查证书是否过期,证书是否替换
function CheckCertificate()
{
    local CertiInfo=$@
    local EXPAND_CONFIG_FILE="/opt/huawei/snas/script/inspect_mml/Certificate.conf"
    local ExpirTime="15552000" #180*24*60*60  过期时间小于等于180天巡检不通过
    local willExpirtTime="31536000" #365*24*60*60 过期时间小于365天，大于180天，巡检建议优化
    local DeadLine=""
    local CertiTime=""
    local tmpDeadline=""
    local isDefaultCerti="YES"
    local IsSoonOutTime="NO"
    local sslcertSHAList="C8:E9:25:F7:34:9D:28:F9:D3:D2:8E:F9:2C:63:90:47:2D:B9:A4:D6 5C:D4:A7:E7:81:B4:F4:F8:35:21:5C:80:6C:B7:B1:C0:E5:8E:CD:24 C3:9E:9D:9E:90:EF:48:13:88:CD:21:5A:41:3F:C2:9B:53:F8:99:50 17:EF:D7:AF:65:D4:21:0E:8B:B9:EA:30:6C:1D:E1:47:B1:CF:06:31"
    local cacertSHAList="3D:8B:B7:90:4D:23:AC:85:51:F7:CC:C2:BF:36:D1:9E:11:10:EE:7D EC:27:82:F7:77:29:BD:94:4D:F5:15:AB:40:16:DD:E5:8C:7B:72:8A 60:B2:B7:BE:EF:2F:83:2C:59:6E:FF:75:CD:4C:F8:2B:19:B0:79:04"
    local clustercertSHAList="F5:CC:07:B0:CC:62:AF:12:87:04:07:F0:5A:30:BA:53:C8:5D:E9:AC 8C:FF:D5:12:F1:73:57:6B:E5:20:E4:CF:64:D6:34:FF:89:1C:2F:FB"
    local keystoreSHAList="FD:FA:98:99:36:B6:DC:00:B1:0A:91:10:CE:F7:8C:CF:AD:19:CA:EB AB:73:D3:8A:F5:BC:23:41:9E:24:91:E4:1A:66:EA:95:26:1C:CE:23 27:69:80:AD:75:16:90:50:87:9B:2F:42:C6:0C:29:82:DF:A7:55:1B"
    local cert_enSHAList="81:4D:66:AA:59:B0:37:99:C7:AA:D9:E3:50:9D:4E:88:6F:2E:DD:8F 36:C9:35:CC:76:72:BD:AF:5E:6D:25:E1:2C:D8:D2:A1:9B:CE:2E:DA"
    local CerName=$( echo ${CertiInfo} | awk -F";" '{print $1}' | awk -F"=" '{print $2}' )
    local Deadline=$( echo ${CertiInfo} | awk -F";" '{print $2}' | awk -F"=" '{print $2}' )
    local SHAkey=$( echo ${CertiInfo} | awk -F";" '{print $3}' | awk -F"=" '{print $2}' )

    #check expiration time
    if [ "XNA" == "X${Deadline}" ];then
        DeadLine="NA"
        IsSoonOutTime="NA"
    else

        CertiTime=$( date -d "${Deadline}" +%s 2>/dev/null )
        if [ $? -ne 0 ];then
            #LOG "Get Seconds Fail! Time para is ${filedate}"
            local zt=$(echo "$Deadline" | awk '{for(i=1; i<=NF; i++) if($i~/^[A-Z]+$/) print $i}')
            if [[ "${zt}" != "" ]] && [[ "${zt}" != " " ]];then
                tmpDeadline=$(echo "$Deadline" | sed "s/${zt}/UTC/g")
                CertiTime="$( date -u -d "${tmpDeadline}" +%s 2>/dev/null )"
                CertiTime=$(getTimeZoneDiffSeconds ${CertiTime})
            fi
        fi
        if [[ "${CertiTime}" == "" ]];then
            echo "[ERR]INFO:Failed to calculate the validity period (${Deadline}) of certificate ${CerName}." >>$RESULTFILE 2>&1
            IsSoonOutTime="--"
            isPass=1
        else
            local passtime=`expr $CertiTime - $curtime`
            if [ $passtime -le ${ExpirTime} ];then   #180*24*60*60  过期时间小于等于180天巡检不通过
                echo "[ERR]INFO:The Certificate ${CerName} valid time(${passtime}s) is less than 180 days(15552000s)." >>$RESULTFILE 2>&1
                IsSoonOutTime="YES"
                isPass=1
            elif [ $passtime -le ${willExpirtTime} ];then   #365*24*60*60 过期时间小于365天，大于180天，巡检建议优化
                echo "[ERR]INFO:The Certificate ${CerName} valid time(${passtime}s) is less than 365 days(31536000)." >>$RESULTFILE 2>&1
                IsSoonOutTime="YES"
                isPass=4
            fi
        fi
    fi

    restore_ifs
    #check if the certificate has been replaced
    checkCertiValueInfo=$(grep "${CerName}" $EXPAND_CONFIG_FILE 2>/dev/null)
    if [ "$checkCertiValueInfo" = "" ];then
        isDefaultCerti="NA" 
    else
        checkVerInfo=`cat $EXPAND_CONFIG_FILE | grep -w "ProductVer"`
        if [ "$checkVerInfo" = "" ]; then
            isDefaultCerti="NA"
        else
            checkVerArray=($checkVerInfo)
            local productversion=$( grep "ProductVersion" /opt/product/deploy/package/version | awk -F"=" '{print $2}')
            itemIndex=$( getVerArrayIndex ${productversion} )
            checkCertiValueArray=(${checkCertiValueInfo})
            DefSHA="${checkCertiValueArray[${itemIndex}]}"
            if [[ "${CerName}" =~ "sslcert.pem" ]];then
                if [[ ${sslcertSHAList} =~ "${SHAkey}" ]];then
                    isDefaultCerti="YES"
                else
                    isDefaultCerti="NO"   
                fi
            elif [[ "${CerName}" =~ "cacert.pem" ]];then
                if [[ ${cacertSHAList} =~ "${SHAkey}" ]];then
                    isDefaultCerti="YES"
                else
                    isDefaultCerti="NO"   
                fi
            elif [[ "${CerName}" =~ "server.keystore" ]];then
                if [[ ${keystoreSHAList} =~ "${SHAkey}" ]];then
                    isDefaultCerti="YES"
                else
                    isDefaultCerti="NO"   
                fi
            elif [[ "${CerName}" =~ "cluster_cert.pem" ]];then
                if [[ ${clustercertSHAList} =~ "${SHAkey}" ]];then
                    isDefaultCerti="YES"
                else
                    isDefaultCerti="NO"
                fi
            elif [[ "${CerName}" =~ "cert_en.pem" ]];then
                if [[ ${cert_enSHAList} =~ "${SHAkey}" ]];then
                    isDefaultCerti="YES"
                else
                    isDefaultCerti="NO"
                fi
            elif [ "${SHAkey}" == "NA" ];then
                isDefaultCerti="NA"
            elif [ "${SHAkey}" != "${DefSHA}" ];then
                isDefaultCerti="NO"
            fi 
        fi
    fi
    set_ifs
echo "CerName:${CerName}||IsSoonOutTime:${IsSoonOutTime}||ExpirationTime:${Deadline}||key:${SHAkey}||IsDefaultCertificate:${isDefaultCerti}" >>$RESULTFILE 2>&1

}
function decode()
{
    local strdecode=$(echo $@ | base64 -d)
    if [ "X" != "${strdecode}" ];then
        echo ${strdecode}
        strdecode=""
        return 0
    fi
    return 1 
}
function checkPubkeyPair()
{
    local ManagementPassphrase="UGsxMjNAc3RvcmFnZQo="
    local DeviceManagerPassphrase="QWRtaW5Ac3RvcmFnZQo="
    local ManagementCertFile="/opt/product/snas/etc/sslcert.pem"
    local ManagementkeyFile="/opt/product/snas/etc/sslkey.pem"
    local DeviceManagerCertFile="/opt/deviceManager/apache/conf/cert_en.pem"
    local DeviceManagerkeyFile="/opt/deviceManager/apache/conf/key_en.pem"
    local certFilePubkey=""
    local keyFilePubkey=""
    if [ "$1" = "Management" ];then
        certFilePubkey=$(openssl x509 -in ${ManagementCertFile} -noout -modulus | openssl sha1)
        keyFilePubkey=$(openssl rsa -in ${ManagementkeyFile} -noout -passin pass:$(decode ${ManagementPassphrase}) -modulus| openssl sha1)
        if [ "${certFilePubkey}" != "${keyFilePubkey}" ] || [[ "${certFilePubkey}" =~ "da39a3ee5e6b4b0d3255bfef95601890afd80709" ]] || [[ "${keyFilePubkey}" =~ "da39a3ee5e6b4b0d3255bfef95601890afd80709" ]];then
            isPass=1
            echo "[ERR]INFO:The Management passphrase or the certificate file ${ManagementCertFile} does not match the private key file ${ManagementkeyFile}." >>$RESULTFILE
        fi
    elif [ "$1" = "DeviceManager" ];then
        certFilePubkey=$(openssl x509 -in ${DeviceManagerCertFile} -noout -modulus | openssl sha1)
        keyFilePubkey=$(openssl rsa -in ${DeviceManagerkeyFile} -noout -passin pass:$(decode ${DeviceManagerPassphrase}) -modulus| openssl sha1)
        if [ "${certFilePubkey}" != "${keyFilePubkey}" ] || [[ "${certFilePubkey}" =~ "da39a3ee5e6b4b0d3255bfef95601890afd80709" ]] || [[ "${keyFilePubkey}" =~ "da39a3ee5e6b4b0d3255bfef95601890afd80709" ]];then
            isPass=1
            echo "[ERR]INFO:The DeviceManager passphrase or the certificate file ${DeviceManagerCertFile} does not match the private key file ${DeviceManagerkeyFile}." >>$RESULTFILE
        fi
    fi
    return 0
}
function CheckAllCertificate()
{
    local subDomain=$( GetDomain )
    local productversion=$( grep "ProductVersion" /opt/product/deploy/package/version | awk -F"=" '{print $2}')
    local IS_S3=$( CheckNodeServiceType )
    local curtime="$( date +%s )"

    #检查节点必然存在证书信息
    local AllCheckPem=$( getALLPem )
    set_ifs
    for Certi in ${AllCheckPem}
    do
        CheckCertificate ${Certi}
    done
    restore_ifs

    #检查节点可能存在证书信息
    local MayBeNonexistPemList=$( getMayBeNonexistPem )
    set_ifs
    for Certi in ${MayBeNonexistPemList}
    do
        CheckCertificate ${Certi}
    done
    restore_ifs

    #检查S3/UDS特有证书信息
    if [ "0" == "${IS_S3}" ];then
       local S3CheckPem=$( getS3Pem )
        set_ifs
        for Certi in ${S3CheckPem}
        do
            CheckCertificate ${Certi}
        done
        restore_ifs
    
        #检查keystore类证书信息
        local S3keyStoreCerti=$( /opt/product/snas/script/inspect_mml/KeyStoreGet "${S3keyStorelist}" )
        set_ifs
        for Certi in ${S3keyStoreCerti}
        do
            CheckCertificate ${Certi}
        done
        restore_ifs
    fi

    #检查0号子域生效证书信息
    if [ "X0" == "X${subDomain}" ];then
        local ZeroPem=$( getZeroPemCerti )
        set_ifs
        for Certi in ${ZeroPem}
        do
            CheckCertificate ${Certi}
        done
        restore_ifs
        checkPubkeyPair DeviceManager
        local DominkeyStoreCerti=$( /opt/product/snas/script/inspect_mml/KeyStoreGet "${DominkeyStorelist}" )
        set_ifs
        for Certi in ${DominkeyStoreCerti}
        do
            CheckCertificate ${Certi}
        done
        restore_ifs
    fi
    sed -i "s/huawei/product/g" $RESULTFILE
    checkPubkeyPair Management
    #打印是否巡检通过
    echo "${CurInspectFun}_Pass $isPass" >>$RESULTFILE
    LOG "${CurInspectFun}_Pass $isPass"

}

CheckAllCertificate

