【问题标题】:Compare duplicate certs in an array and delete matches with the oldest expirations dates比较数组中的重复证书并删除过期日期最早的匹配项
【发布时间】:2021-05-13 19:56:53
【问题描述】:

我正在编写一个新脚本来管理 macOS 中的重复证书。

我剩下的一项未解决的任务涉及以下步骤:

1 解析 macOS 系统钥匙串,获取与名称“my_certificate”匹配的所有证书。我的工作如下所示

2 如果只有 1 个名为“my_certificate”的证书,则退出 0。无需担心重复。

3 如果有超过 1 个名为“my_certificate”的证书(即存在重复),则比较所有到期日期并进行相应排序。

4 仅保留最新的证书并删除过期日期较早的任何重复项。我有根据 SHA-1 哈希删除证书的代码。

我拥有如何与系统钥匙串交互的所有 Mac 特定逻辑(解析、删除等 - 这是我一直在做的事情)。

我已经有删除 EXPIRED 证书的逻辑(它在此脚本的前面运行,但在我的示例中未显示,因此只有有效的重复项需要处理)。

            #!/bin/sh
            
            IFS=","
                
                CERT_LIST=$( security find-certificate -a -c "my_certificate" -p -Z "/Library/Keychains/System.keychain" | sed s/"-----END CERTIFICATE-----"/"-----END CERTIFICATE-----,"/g)
                
                if [[ -n "${CERT_LIST}" ]]; then
                    
                    CERT_ARRAY=(${CERT_LIST})
                    
                    for CERT_ELEMENT in "${CERT_ARRAY[@]}"; do
                            
                        CERT_EXPIRATION_DATE_FULL=$( openssl x509 -noout -enddate <<< "${CERT_ELEMENT}" | cut -f2 -d= )
                        CERT_EXPIRATION_DATE_FORMATTED=$( date -j -f "%b %d %T %Y %Z" "${CERT_EXPIRATION_DATE_FULL}" "+%Y-%m-%d" )
                        CERT_EXPIRATION_DATE_FORMATTED_TRUNCATED=$( echo ${CERT_EXPIRATION_DATE_FORMATTED} | tr -d "-" )        
                        CERT_SHA1_HASH=$( grep -e 'SHA-1 hash:' <<< "${CERT_ELEMENT}" | cut -d" "  -f3- )
                        CERT_ARRAY_INDEX_NUMBER=$((${CERT_ARRAY_INDEX_NUMBER}+1))
                
                        echo "QA testing: Certificate (${CERT_ARRAY_INDEX_NUMBER}): Hash: ${CERT_SHA1_HASH} Expiration date: ${CERT_EXPIRATION_DATE_FORMATTED_TRUNCATED}"
                
                        
    #I'm stuck HERE
    # at the process of examining the remaining duplicate certs, 
    # and determining which cert is the 'newest' one to keep.
    # I have all the cert data I need at this point.
        
        
                    done
                    
                else
                    
                    echo "Error: Certificate "my_certificate" could not be found."
                    exit 1
                    
                fi
exit 0

我的 QA 数据示例在标准输出(用于测试)中如下所示:

证书(1):哈希:C65CC29A9EDFCB6AA00A3FC0E64ED32084624A56 到期日期:20220503

证书(2):哈希:B0C2D933C09E29DCA09F4EB8099B4D11F6DE3E86 到期日期:20220507

【问题讨论】:

    标签: arrays bash macos date certificate


    【解决方案1】:

    假设一个数组certs持有cert data,会实现 通过将 for 循环中的 echo "QA testing: Certificate.. 行替换为:

    certs+=("echo "QA testing: Certificate..")
    

    那请试一试:

    # the assignment below is just for demo and they should be assigned in the loop
    certs=(
      'QA testing: Certificate (1): Hash: C65CC29A9EDFCB6AA00A3FC0E64ED32084624A56 Expiration date: 20220503'
      'QA testing: Certificate (2): Hash: B0C2D933C09E29DCA09F4EB8099B4D11F6DE3E86 Expiration date: 20220507')
    
    # put the code below after the loop "for CERT_ELEMENT in "${CERT_ARRAY[@]}"; do .. done"
    mapfile -t certs_sorted < <(printf "%s\n" "${certs[@]}" | awk '{print $NF, $0}' | sort -nrk1,1 | sed 's/^[0-9]* //')
    

    现在"${certs_sorted[0]}"拥有最新的证书和 "${certs_sorted[@]:1}" 持有旧的。

    按照惯例,建议用户变量名使用小写。

    [编辑]
    如果mapfile 不可用,请将mapfile 行替换为以下内容:

    while IFS= read -r line; do
        certs_sorted+=("$line")
    done < <(printf "%s\n" "${certs[@]}" | awk '{print $NF, $0}' | sort -nrk1,1 | sed 's/^[0-9]* //')
    

    它也将数组 certs_sorted 分配给已排序的证书。
    如果进程替换 &lt;(command) 不可用,这里有一个替代方案:

    lines=$(printf "%s\n" "${certs[@]}" | awk '{print $NF, $0}' | sort -nrk1,1 | sed 's/^[0-9]* //')
    while IFS= read -r line; do
        certs_sorted+=("$line")
    done <<< "$lines"
    

    【讨论】:

    • 感谢您的建议。不幸的是,mapfile 实用程序在我的 macOS 发行版中不可用,我无法在任何开源存储库(自制软件等)中找到它
    • 感谢您的反馈。我已经用替代方法更新了我的答案。请你试试看好吗? BR。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-16
    相关资源
    最近更新 更多