2017-07-21 33 views
1

我見過一個例子,下面的例子使用openssl下載一個證書,但我正在尋找一個下載整個證書鏈並將每個證書保存爲一個單獨文件的例子。理想情況下,保存與CN的名稱匹配的每個證書文件將是非常好的。openssl的腳本/包裝器將下載整個證書鏈,並將每個證書保存到一個serparate文件中?

echo -n | openssl s_client -connect HOST:PORTNUMBER | \ 
    sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > /tmp/$SERVERNAME.cert 
+0

Stack Overflow是編程和開發問題的網站。這個問題似乎是無關緊要的,因爲它要求提供軟件或程序建議。請參閱幫助中心的[我可以詢問哪些主題](http://stackoverflow.com/help/on-topic)。也許[Software Recommendations Stack Exchange](http://softwarerecs.stackexchange.com/)會是一個更好的地方。或者[Rent A Coder](http://www.rentacoder.com)或[Freelancer](http://www.freelancer.com)可以幫助你。 – jww

回答

3

通常,我不喜歡「爲我寫一個程序」類型的請求,但在這種情況下,我意識到我想自己擁有這樣的東西,所以我繼續寫下來。這不是特別精緻,它只是將證書轉儲到當前目錄中。我所做的一件好事是它會自動爲openssl s_client支持的非SSL服務(即smtp,imap,pop3,ftp和xmpp)啓用適當的starttls模式。 。它還包括在證書文件中(在-----BEGIN CERTIFICATE-----行之前)openssl打印每個證書主題和發行人的摘要。

#!/bin/bash 

# Connect to an SSL service and extract its certificates to files in the 
# current directory. 

usage() { 
    echo "Usage:" >&2 
    echo " $(basename "$0") server[:port] [other s_client flags]" >&2 
    echo " $(basename "$0") protocol://server [other s_client flags]" >&2 
    exit 1 
} 


# Parse command-line arguments 
openssl_options=() 
if (($# < 1)); then # No server address specified 
    usage 

elif [[ "$1" = *://* ]]; then # proto://domain format 
    port="${1%%://*}" # Just use the protocol name as the port; let openssl look it up 
    server="${1#*://}" 
    server="${server%%/*}" 

elif [[ "$1" = *:* ]]; then # Explicit port number supplied 
    port="${1#*:}" 
    server="${1%:*}" 

else # No port number specified; default to 443 (https) 
    server="$1" 
    port=443 
fi 

# If the protocol/port specified is a non-SSL service that s_client supports starttls for, enable that 
if [[ "$port" = "smtp" || "$port" = "pop3" || "$port" = "imap" || "$port" = "ftp" || "$port" = "xmpp" ]]; then 
    openssl_options+=(-starttls "$port") 
elif [[ "$port" = "imap3" ]]; then 
    openssl_options+=(-starttls imap) 
elif [[ "$port" = "pop" ]]; then 
    port=pop3 
    openssl_options+=(-starttls pop3) 
fi 


# Any leftover command-line arguments get passed to openssl s_client 
shift 
openssl_options+=("[email protected]") 

# Try to connect and collect certs 
connect_output=$(openssl s_client -showcerts -connect "$server:$port" "${openssl_options[@]}" </dev/null) || { 
    status=$? 
    echo "Connection failed; exiting" >&2 
    exit $status 
} 
echo 

nl=$'\n' 

state=begin 
while IFS= read -r line <&3; do 
    case "$state;$line" in 
     "begin;Certificate chain") 
     # First certificate is about to begin! 
     state=reading 
     current_cert="" 
     certname="" 
     ;; 

     "reading;-----END CERTIFICATE-----") 
     # Last line of a cert; save it and get ready for the next 
     current_cert+="${current_cert:+$nl}$line" 

     # Pick a name to save the cert under 
     if [[ "$certname" = */CN=* ]]; then 
      certfile="${certname#*/CN=}" 
      certfile="${certfile%%/*}" 
      certfile="${certfile// /_}.crt" 
     elif [[ -n "$certname" && "$certname" != "/" ]]; then 
      certfile="${certname#/}" 
      certfile="${certfile//\//:}" 
      certfile="${certfile// /_}.crt" 
     else 
      echo "???No name found for certificate" >&2 
      certfile="Unknown_certificate.crt" 
     fi 

     # ...and try to save it 
     if [[ -e "$certfile" ]]; then 
      echo "Already exists: $certfile" >&2 
     else 
      echo "Saving cert: $certfile" 
      echo "$current_cert" >"$certfile" 
     fi 

     state=reading 
     current_cert="" 
     certname="" 
     ;; 

     "reading; "*" s:"*) 
     # This is the cert subject summary from openssl 
     certname="${line#*:}" 
     current_cert+="${current_cert:+$nl}Subject: ${line#*:}" 
     ;; 

     "reading; "*" i:"*) 
     # This is the cert issuer summary from openssl 
     current_cert+="${current_cert:+$nl}Issuer: ${line#*:}" 
     ;; 

     "reading;---") 
     # That's the end of the certs... 
     break 
     ;; 

     "reading;"*) 
     # Otherwise, it's a normal part of a cert; accumulate it to be 
     # written out when we see the end 
     current_cert+="$nl$line" 
     ;; 
    esac 
done 3<<< "$connect_output" 
+0

必要性是發明之母 - 或者在這種情況下是一個方便腳本的母親。做得好。 –

+0

壞屁股! 我認爲這已經存在,但找不到像這樣的東西。幹得好先生! – Inetquestion

0

OpenSSL docs

-showcerts:顯示整個服務器證書鏈:通常僅顯示自身服務器證書。

如果你真的需要多個文件,你只需要通過每個證書的開頭匹配(類似於正則表達式的一個在你的命令)使用類似csplit(或awk)你的命令的輸出分配。