Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game. |
| Notices |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
 |
GNU/Linux Basic Guide
This 255-page guide will provide you with the keys to understand the philosophy of free software, teach you how to use and handle it, and give you the tools required to move easily in the world of GNU/Linux. Many users and administrators will be taking their first steps with this GNU/Linux Basic guide and it will show you how to approach and solve the problems you encounter.
Click Here to receive this Complete Guide absolutely free. |
|
 |
11-10-2012, 03:56 AM
|
#1
|
|
Member
Registered: Jul 2008
Posts: 103
Rep:
|
Check certificate of a server
To make it easy to troubleshoot an SSL certificate I wrote this little script. It connects to the server reading its certificate and gives the most important info giving warnings with colors. It also verifies the certificate against a downloadable CA bundle (apt-get install ca-certificates && update-ca-certificates)
There's an awkward part (the while loop) in the script where I spawn the openssl request. It's there because I developed this script from another script I wrote (certexpire) to be used on a Zabbix server (monitoring system like Nagios). For this script it was imperative to always have an output.
I also have a question regarding SSL.
I have a server where I'm running pound (reverse proxy) which has 2 certificates loaded. One for domain1 and another for domain2. It uses TLS and it works for IE, Chrome and Firefox.
Because I can't instruct openssl to use TLS my pound only gives the first certificate. TLS works for smtp, pop and imap.
Is it correct that I can't use TLS over http?
If so, is it a strange questions to ask the developers of openssl to support this?
Well, here's the script:
cat /usr/local/sbin/certinfo
Code:
#!/bin/bash
export PATH=${PATH}:/usr/local/sbin:/sbin:/usr/sbin:/bin:/usr/bin
TIMEOUT=10
RETVAL=3
# location on Debian based Linux, run "update-ca-certificates" if you don't have them
CAfile=/etc/ssl/certs/ca-certificates.crt
# Try Redhat based
[ -e "${CAfile}" ] || CAfile=/etc/pki/tls/certs/ca-bundle.crt
if [ ! -e "${CAfile}" ] ; then
echo "No Certificate Authority Bundle found" >&2
exit 1
fi
# If called by zabbix, handle some things different
if echo "${BASH_SOURCE}" | grep -q "zabbix" ; then
# get rid of 1st parameter (on Zabbix 1.8x)
# shift 1
# Change TimeOut value to the one in /etc/zabbix/zabbix_server.conf
ZABBIX_TIMEOUT=`grep -i '^Timeout' /etc/zabbix/zabbix_server.conf 2>/dev/null | awk -F= '{print $2}' | tr -cd '0-9'`
if [ -z "${ZABBIX_TIMEOUT}" ] ; then
TIMEOUT=3
else
# Let's take 1 second less than the one in /etc/zabbix/zabbix_server.conf and just hope to be in time
TIMEOUT=$(( ${ZABBIX_TIMEOUT} - 1 ))
fi
fi
# Zabbix 2.0 sends parameters quoted, where < 1.9 sends them unquoted
# This way it works on both
HOST=`echo "$*" | awk '{print $1}' | tr 'A-Z' 'a-z'`
PORT=`echo "$*" | awk '{print $2}' | tr -cd '0-9'`
SCRATCH=`mktemp`
TMP1=`mktemp`
TMP2=`mktemp`
esc="\033["
RED="31;40;1m"
GREEN="32;40;1m"
[ -z "${HOST}" ] && exit 1
[ -z "${PORT}" ] && PORT=443
HOSTWITHIP=${HOST}
IP=${HOST}
if echo "${HOST}" | grep -q '[a-z]' ; then
IP=`host -t A ${HOST} | egrep -o 'has address [0-9.]+' | head -n1 | awk '{print $3}'`
HOSTWITHIP="${HOST} (${IP})"
if [ -z "${IP}" ] ; then
echo "${esc}${RED}Error resolving ${HOST}${esc}0m"
exit 1
fi
fi
# openssl is able to check plain smtp/pop3/ftp/imap connections
# that use TLS to setup a secure connection
TLS=
echo "${PORT}" | egrep -q '^(25|587)$' && TLS="-crlf -starttls smtp"
echo "${PORT}" | egrep -q '^110$' && TLS="-starttls pop3"
echo "${PORT}" | egrep -q '^21$' && TLS="-starttls ftp"
echo "${PORT}" | egrep -q '^143$' && TLS="-starttls imap"
# Retrieve Certificate in background because it doesn't support TimeOuts
# exec 2>/dev/null doesn't seem to be necessary if called this way....
echo "" | openssl s_client -verify 3 -CAfile ${CAfile} -connect ${IP}:${PORT} ${TLS} 2>/dev/null >${SCRATCH} &
sleep .1
# double the TIMEOUT and wait for half a second each time
let TIMEOUT*=2
# Wait for certificate
n=1
while [ ! -s ${SCRATCH} ] ; do
sleep .48
[ $n -ge ${TIMEOUT} ] && break
let n++
done
# If we have retrieved the certificate, we'll process it and retrieve the domain names
if [ -s ${SCRATCH} ] ; then
sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' ${SCRATCH} | openssl x509 -text -noout 2>/dev/null >${TMP1}
#cat ${TMP1}
REMARK=
[ -z "${TLS}" ] || REMARK="(using TLS)"
echo -e "\nCertificate info for host ${esc}${GREEN}${HOSTWITHIP}${esc}0m on port ${PORT} ${esc}${GREEN}${REMARK}${esc}0m\n"
CN=`grep -i "Subject:" ${TMP1} | egrep -o 'CN=[A-Za-z0-9=:/. @_-]+' | awk -F= '{print $2}'`
echo " CN: ${CN}"
echo -e '\n Subject:'
grep -i "Subject:" ${TMP1} | egrep -o '[A-Z]+=[A-Za-z0-9=:/. @_-]+' | sed 's/.*/ &/'
grep -i 'Verify return code' ${SCRATCH} | grep -qi '(ok)' || echo -e " ${esc}${RED}Not certified by an Authority!!${esc}0m"
echo ' Issuer:'
# grep -i "Issuer:" ${TMP1}
grep -i "Issuer:" ${TMP1} | egrep -o '[A-Z]+=[A-Za-z0-9=:/. @_-]+' | sed 's/.*/ &/'
echo -e "\n Validity:"
FROM_DATE=`grep -io 'Not Before.*' ${TMP1} | head -n1 | awk -F: '{print $2":"$3":"$4}'`
[ ! -z "${FROM_DATE}" ] && [ `date -d "${FROM_DATE}" +%s` -ge `date +%s` ] && echo -en "${esc}${RED}"
echo -e " Valid since: ${FROM_DATE}${esc}0m"
EXPIRE_DATE=`grep -io 'Not After.*' ${TMP1} | head -n1 | awk -F: '{print $2":"$3":"$4}'`
if [ ! -z "${EXPIRE_DATE}" ] ; then
[ `date -d "${EXPIRE_DATE}" +%s` -lt `date -d "next month" +%s` ] && echo -en "${esc}${GREEN}"
[ `date -d "${EXPIRE_DATE}" +%s` -lt `date +%s` ] && echo -en "${esc}${RED}"
fi
echo -e " Expires on: ${EXPIRE_DATE}${esc}0m"
# Create a greplist with DNS names converted to regular expressions
egrep -o 'DNS:[*a-z0-9.-]+' ${TMP1} | awk -F: '{print $2}' | sed 's/\./\\./g;s/*/.*/g;s/.*/^&$/g' >${TMP2}
echo -e "\nDNS names: "
if [ -s ${TMP2} ] ; then
echo "${HOST}" | grep -qf ${TMP2} || echo -e " ${esc}${RED}Name Mismatch!!${esc}0m no DNS name matches ${esc}${GREEN}${HOST}${esc}0m"
egrep -o 'DNS:[*a-z0-9.-]+' ${TMP1} | awk -F: '{print $2}' | sed 's/.*/ &/'
else
# There are NO DNS names, put CN in the greplist
echo -en "${CN}" | sed 's/\./\\./g;s/*/.*/g;s/.*/^&$/g' >${TMP2}
echo -e " ${esc}${RED}No DNS names in certificate${esc}0m\n"
if echo "${HOST}" | grep -qf ${TMP2} ; then
echo -e " ${esc}${GREEN}${HOST} matches CN${esc}0m"
else
echo -e " ${esc}${GREEN}${HOST} ${esc}${RED}does NOT match CN${esc}0m"
fi
fi
echo -e '\n'
else
# Too late you lazy bastard, I might as well kill you...
kill -9 %1 2>/dev/null
fi
rm -f ${SCRATCH} 2>/dev/null
rm -f ${TMP1} 2>/dev/null
rm -f ${TMP2} 2>/dev/null
|
|
|
|
11-11-2012, 10:37 AM
|
#2
|
|
Moderator
Registered: May 2001
Posts: 24,779
|
Quote:
Originally Posted by frater
I can't instruct openssl to use TLS
|
'man s_client'?
Quote:
Originally Posted by frater
Code:
# Zabbix 2.0 sends parameters quoted, where < 1.9 sends them unquoted
# This way it works on both
HOST=`echo "$*" | awk '{print $1}' | tr 'A-Z' 'a-z'`
PORT=`echo "$*" | awk '{print $2}' | tr -cd '0-9'`
|
To remove for example single quotes you could:
Code:
HOST="$1"; HOST=${HOST//\'/}
Quote:
Originally Posted by frater
Code:
SCRATCH=`mktemp`
TMP1=`mktemp`
TMP2=`mktemp`
|
If you need several temp files it could be easier to create a temporary directory and put them all inside that? I also prefer using I/O-less /dev/shm as temp root.
Code:
_MYTMPDIR=`mktemp -p /dev/shm -d scriptname.XXXXXXXXXX` && {
output0 > "${_MYTMPDIR}/tempfile0"
output1 > "${_MYTMPDIR}/tempfile1"
rm -rf "${_MYTMPDIR}"
} # All temporary files gone now.
Quote:
Originally Posted by frater
Code:
[ -z "${PORT}" ] && PORT=443
|
You could set a default at the beginning of the script:
or force the default if not declared:
Quote:
Originally Posted by frater
Code:
HOSTWITHIP=${HOST}
IP=${HOST}
if echo "${HOST}" | grep -q '[a-z]' ; then
IP=`host -t A ${HOST} | egrep -o 'has address [0-9.]+' | head -n1 | awk '{print $3}'`
HOSTWITHIP="${HOST} (${IP})"
if [ -z "${IP}" ] ; then
echo "${esc}${RED}Error resolving ${HOST}${esc}0m"
exit 1
fi
fi
|
Some hosts may have multiple IP addresses. How about :
Code:
IP=${HOST}; if [ "${HOST}" != "${HOST//[a-z]/}" ]; then
IPLIST=($(dig +nocomments +noquestion +nostats +nocmd +noauth +noadditional -t A ${HOST} 2>/dev/null| awk '/IN.*A/ {print $NF}'))
if [ ${#IPLIST[@]} -ne 0 ]; then
for (( i = 0 ; i < ${#IPLIST[@]}; i++ ));do
echo "${HOST} (${IPLIST[$i]})"
done
else
echo "${esc}${RED}Error resolving ${HOST}${esc}0m"; exit 1
fi
fi
Quote:
Originally Posted by frater
Code:
# openssl is able to check plain smtp/pop3/ftp/imap connections
# that use TLS to setup a secure connection
TLS=
echo "${PORT}" | egrep -q '^(25|587)$' && TLS="-crlf -starttls smtp"
echo "${PORT}" | egrep -q '^110$' && TLS="-starttls pop3"
echo "${PORT}" | egrep -q '^21$' && TLS="-starttls ftp"
echo "${PORT}" | egrep -q '^143$' && TLS="-starttls imap"
|
How about a case statement instead:
Code:
case "${PORT}" in
21) TLS="-starttls ftp";;
25|587) TLS="-crlf -starttls smtp";;
110) TLS="-starttls pop3";;
143) TLS="-starttls imap";;
esac
Just suggestions, OK?
|
|
|
|
11-13-2012, 05:47 AM
|
#3
|
|
Member
Registered: Jul 2008
Posts: 103
Original Poster
Rep:
|
Thanks (again) for all the tips...
But the main question remains unanswered.
I'm already using TLS and it is working for FTP, IMAP, POP3 and SMTP
I also would like to use it to test http with TLS
http is not mentioned as a protocol and I was wondering if I could write around it.....
BTW...
Your remark about hosts having more than 1 IP.
I solved it in the original script by using 'head -n1'
Does your code deliver a different IP each time (round robin??)?
Last edited by frater; 11-13-2012 at 05:53 AM.
|
|
|
|
11-13-2012, 08:07 AM
|
#4
|
|
Member
Registered: Oct 2012
Distribution: OpenSuSE,RHEL,OpenBSD
Posts: 495
Rep: 
|
|
|
|
1 members found this post helpful.
|
11-13-2012, 09:00 AM
|
#5
|
|
Moderator
Registered: May 2001
Posts: 24,779
|
Quote:
Originally Posted by frater
But the main question remains unanswered.
I'm already using TLS and it is working for FTP, IMAP, POP3 and SMTP
I also would like to use it to test http with TLS
http is not mentioned as a protocol and I was wondering if I could write around it.....
|
Ah, now I see where the misunderstanding came from in your OP:
Quote:
Originally Posted by frater
Because I can't instruct openssl to use TLS my pound only gives the first certificate. TLS works for smtp, pop and imap.
Is it correct that I can't use TLS over http?
|
You don't mean TLS as in:
Code:
~]$ echo -n | openssl s_client -connect www.google.com:443 2>&1|awk '/Protocol/ {print $3}'
TLSv1
~]$ echo -n | openssl s_client -no_tls1 -connect www.google.com:443 2>&1|awk '/Protocol/ {print $3}'
SSLv3
but STARTTLS, in other words upgrading a plain text protocol to an encrypted one.
For HTTP there's the theoretical RFC 2817, a suggestion Apache may use:
Code:
<VirtualHost _default_:80>
SSLEngine optional
</VirtualHost>
and mozilla 276813.
But that's about it.
(Short answer: no.)
Quote:
Originally Posted by frater
Your remark about hosts having more than 1 IP.
I solved it in the original script by using 'head -n1'
Does your code deliver a different IP each time (round robin??)?
|
You didn't "solve" it: you just chose to ignore the other IP addresses ;-p
My snippet just loops over all IPv4 addresses returned and using it in a RR or other fashion is, like they say, "left as an exercise for the reader".
|
|
|
1 members found this post helpful.
|
11-17-2012, 04:31 AM
|
#6
|
|
Member
Registered: Jul 2008
Posts: 103
Original Poster
Rep:
|
Quote:
Originally Posted by linosaurusroot
|
I didnᷰt find any info there I wasnᷰt already using...
I already have a web-server running on port 443 which can deliver the certificate for domain1.com if one connects with the hostname domain1.com and it gives the certificate for domain2.com if the browser connects using domain2.com. If the browser is connecting in the classical way, it will always give the certificate for domain1.com.
The mechanism is similar to the TLS with smtp, imap and other protocols. I donᷰt know the details of this mechanism. What I do know is that it is working with all popular browsers.
The problem I want to solve is this:
I wrote this script that tests certificates. If itᷰs connecting to the well known ports of plain smtp, pop3, ftp and imap, it will use the opensslᷰs option to use TLS
openssl doesnᷰt have support for http, although such a mechanism does exist.
Maybe it s something I could write around?
Anyone knows something about the ins and outs of this protocol and help me out?
|
|
|
|
11-18-2012, 07:00 AM
|
#7
|
|
Member
Registered: Jul 2008
Posts: 103
Original Poster
Rep:
|
It turns out I asked the wrong question.
I should have asked about SNI (Server Name Indication).
It's not TLS at all what's doing this, which is good as I heard there are some security issues with TLS.
The https-server is supporting SNI and I merely have to give OpenSSL the extra option "-servername hostname"
Code:
echo "" | openssl s_client -verify 3 -CAfile ${CAfile} -servername ${HOST} -connect ${IP}:${PORT} ${TLS}
|
|
|
|
11-18-2012, 07:12 AM
|
#8
|
|
Member
Registered: Jul 2008
Posts: 103
Original Poster
Rep:
|
@ unSpawn: Thanks for the suggestions. I very much appreciate your efforts to show me how I can improve my coding with bash.
Although I haven't followed all suggestions in this one, I will consider them in future scripts.
This script is now working for my site which uses SNI to present the proper certificate.
# cat /usr/local/sbin/certinfo
Code:
#!/bin/bash
export PATH=${PATH}:/usr/local/sbin:/sbin:/usr/sbin:/bin:/usr/bin
TIMEOUT=10
RETVAL=3
# location on Debian based Linux, run "update-ca-certificates" if you don't have them
CAfile=/etc/ssl/certs/ca-certificates.crt
# Try Redhat based
[ -e "${CAfile}" ] || CAfile=/etc/pki/tls/certs/ca-bundle.crt
if [ ! -e "${CAfile}" ] ; then
echo "No Certificate Authority Bundle found" >&2
exit 1
fi
# If called by zabbix, handle some things different
if echo "${BASH_SOURCE}" | grep -q "zabbix" ; then
# get rid of 1st parameter (on Zabbix 1.8x)
# shift 1
# Change TimeOut value to the one in /etc/zabbix/zabbix_server.conf
ZABBIX_TIMEOUT=`grep -i '^Timeout' /etc/zabbix/zabbix_server.conf 2>/dev/null | awk -F= '{print $2}' | tr -cd '0-9'`
if [ -z "${ZABBIX_TIMEOUT}" ] ; then
TIMEOUT=3
else
# Let's take 1 second less than the one in /etc/zabbix/zabbix_server.conf and just hope to be in time
TIMEOUT=$(( ${ZABBIX_TIMEOUT} - 1 ))
fi
fi
# Zabbix 2.0 sends parameters quoted, where < 1.9 sends them unquoted
# This way it works on both
HOST=`echo "$*" | awk '{print $1}' | tr 'A-Z' 'a-z'`
PORT=`echo "$*" | awk '{print $2}' | tr -cd '0-9'`
SCRATCH=`mktemp`
TMP1=`mktemp`
TMP2=`mktemp`
esc="\033["
RED="31;40;1m"
GREEN="32;40;1m"
[ -z "${HOST}" ] && exit 1
[ -z "${PORT}" ] && PORT=443
HOSTWITHIP=${HOST}
IP=${HOST}
if [ "${HOST}" != "${HOST//[a-z]/}" ]; then
IP=`host -t A ${HOST} 2>/dev/null | egrep -o 'has address [0-9.]+' | head -n1 | awk '{print $3}'`
HOSTWITHIP="${HOST} (${IP})"
if [ -z "${IP}" ] ; then
echo -e "${esc}${RED}Error resolving ${HOST}${esc}0m" >&2
exit 1
fi
fi
# openssl is able to check plain smtp/pop3/ftp/imap connections
# that use TLS to setup a secure connection
TLS=
case "${PORT}" in
21) TLS="-starttls ftp";;
25|587) TLS="-crlf -starttls smtp";;
110) TLS="-starttls pop3";;
143) TLS="-starttls imap";;
esac
# Retrieve Certificate in background because it doesn't support TimeOuts
# exec 2>/dev/null doesn't seem to be necessary if called this way....
echo "" | openssl s_client -verify 3 -CAfile ${CAfile} -servername ${HOST} -connect ${IP}:${PORT} ${TLS} 2>/dev/null >${SCRATCH} &
sleep .1
# double the TIMEOUT and wait for half a second each time
let TIMEOUT*=2
# Wait for certificate
n=1
while [ ! -s ${SCRATCH} ] ; do
sleep .48
[ $n -ge ${TIMEOUT} ] && break
let n++
done
# If we have retrieved the certificate, we'll process it and retrieve the domain names
if [ -s ${SCRATCH} ] ; then
sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' ${SCRATCH} | openssl x509 -text -noout 2>/dev/null >${TMP1}
#cat ${TMP1}
REMARK=
[ -z "${TLS}" ] || REMARK="(using TLS)"
echo -e "\nCertificate info for host ${esc}${GREEN}${HOSTWITHIP}${esc}0m on port ${PORT} ${esc}${GREEN}${REMARK}${esc}0m\n"
CN=`grep -i "Subject:" ${TMP1} | egrep -o 'CN=[A-Za-z0-9=:/. @_-]+' | awk -F= '{print $2}'`
echo " CN: ${CN}"
echo -e '\n Subject:'
grep -i "Subject:" ${TMP1} | egrep -o '[A-Z]+=[A-Za-z0-9=:/. @_-]+' | sed 's/.*/ &/'
grep -i 'Verify return code' ${SCRATCH} | grep -qi '(ok)' || echo -e " ${esc}${RED}Not certified by an Authority!!${esc}0m"
echo ' Issuer:'
# grep -i "Issuer:" ${TMP1}
grep -i "Issuer:" ${TMP1} | egrep -o '[A-Z]+=[A-Za-z0-9=:/. @_-]+' | sed 's/.*/ &/'
echo -e "\n Validity:"
FROM_DATE=`grep -io 'Not Before.*' ${TMP1} | head -n1 | awk -F: '{print $2":"$3":"$4}'`
[ ! -z "${FROM_DATE}" ] && [ `date -d "${FROM_DATE}" +%s` -ge `date +%s` ] && echo -en "${esc}${RED}"
echo -e " Valid since: ${FROM_DATE}${esc}0m"
EXPIRE_DATE=`grep -io 'Not After.*' ${TMP1} | head -n1 | awk -F: '{print $2":"$3":"$4}'`
if [ ! -z "${EXPIRE_DATE}" ] ; then
[ `date -d "${EXPIRE_DATE}" +%s` -lt `date -d "next month" +%s` ] && echo -en "${esc}${GREEN}"
[ `date -d "${EXPIRE_DATE}" +%s` -lt `date +%s` ] && echo -en "${esc}${RED}"
fi
echo -e " Expires on: ${EXPIRE_DATE}${esc}0m"
# Create a greplist with DNS names converted to regular expressions
egrep -o 'DNS:[*A-Za-z0-9.-]+' ${TMP1} | awk -F: '{print $2}' | sed 's/\./\\./g;s/*/.*/g;s/.*/^&$/g' >${TMP2}
echo -e "\nDNS names: "
if [ -s ${TMP2} ] ; then
echo "${HOST}" | grep -qif ${TMP2} || echo -e " ${esc}${RED}Name Mismatch!!${esc}0m no DNS name matches ${esc}${GREEN}${HOST}${esc}0m"
egrep -o 'DNS:[*a-zA-Z0-9.-]+' ${TMP1} | awk -F: '{print $2}' | sed 's/.*/ &/'
else
# There are NO DNS names, put CN in the greplist
echo -en "${CN}" | tr 'A-Z' 'a-z' | sed 's/\./\\./g;s/*/.*/g;s/.*/^&$/g' >${TMP2}
echo -e " ${esc}${RED}No DNS names in certificate${esc}0m\n"
if echo "${HOST}" | grep -qif ${TMP2} ; then
echo -e " ${esc}${GREEN}${HOST} matches CN${esc}0m"
else
echo -e " ${esc}${GREEN}${HOST} ${esc}${RED}does NOT match CN ${CN}${esc}0m"
fi
fi
echo -e '\n'
else
# Too late you lazy bastard, I might as well kill you...
kill -9 %1 2>/dev/null
fi
rm -f ${SCRATCH} 2>/dev/null
rm -f ${TMP1} 2>/dev/null
rm -f ${TMP2} 2>/dev/null
Last edited by frater; 11-18-2012 at 07:16 AM.
|
|
|
|
| Thread Tools |
Search this Thread |
|
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -5. The time now is 09:23 PM.
|
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|