Install openssl-1.1.0 on CentOS7

I really wanted the -proxy flag on the openssl command. It’s not available in the provided openssl package (1.0.1 series), but it is in the 1.1.0 which is now the base package in Fedora. But for the Enterprise Linux users, you need to do a little bit of work to get it.

Download a pre-compiled package

You could just download the package from my copr. Save the contents of the .repo file [copr.fedorainfracloud.org] or use them from here.

[bgstack15-stackrpms]
name=Copr repo for stackrpms owned by bgstack15
baseurl=https://copr-be.cloud.fedoraproject.org/results/bgstack15/stackrpms/epel-7-$basearch/
type=rpm-md
skip_if_unavailable=True
gpgcheck=1
gpgkey=https://copr-be.cloud.fedoraproject.org/results/bgstack15/stackrpms/pubkey.gpg
repo_gpgcheck=0
enabled=1
enabled_metadata=1

Install with:

yum install openssl110

And then the binary has been named openssl110

Download and compile the source

wget https://www.openssl.org/source/openssl-1.1.0i.tar.gz
tar -zxf openssl-1.1.0i.tar.gz
cd openssl-1.1.0i
./config
make
sudo make install

To prevent an error that resembles:

/usr/local/bin/openssl version
/usr/local/bin/openssl: error while loading shared libraries: libcrypto.so.1.1: cannot open shared object file: No such file or directory

You have to provide the library files in a directory that the dynamic linker is looking in. There are multiple ways to tackle this.

Option 1: update library path

Add the directory containing the libcrypt.so.1.1 and similar files to the LD_LIBRARY_PATH environment variable.

export LD_LIBRARY_PATH=/usr/local/lib64:${LD_LIBRARY_PATH}

Option 2: move library files to lib directory

Or just move the files to the main library location. On a x86_64 system, that would be:

mv libcrypto.so.1.1 libssl.so.1.1 /usr/lib64/

References

Weblinks

Internet search openssl s_client http proxy [duckduckgo.com]
openssl s_client using a proxy [stackoverflow.com]
How to update openssl 1.1.0 in Centos 6.9/7.0 [linuxscriptshub.com]

Advertisements

Automated certreq for GNU/Linux

Last updated 2018-11-14

Background

Microsoft provides the certreq utility for its non-free operating system. This tool makes it easy to get certificates from the Microsoft sub-CA on your network.

GNU Linux hosts do not get that tool, so a viable alternative is to script the interaction with the website. My content in this post is shamelessly ripped from a StackOverflow post and beefed up.

In my research, I came across a question: “How to submit certificate request from red hat to windows ca“.

The solution

Dependencies

Certreq needs the framework.sh shell library available from my bgscripts package. At the very least, you need framework.sh, which you can place either in the same directory as certreq.sh or you can modify the framework lookup paths in the script to point to where you placed it.
This will solve the issue “certreq.sh: validateparams: not found.”

The script

I present my shell script, certreq.sh.
This shell script:

  • Generates CSR and submits it to the Microsoft Sub-CA.
  • Saves private key, public key (the certificate), and cert chain to a temporary directory
  • Removes the temp directory after 5 minutes automatically to remove the private key
  • Sends to standard out the file names and purposes, for consumption by automation tool, e.g., ansible

Code walkthrough

Instead of copying and pasting the whole code here, I will discuss only snippets.
Here is the usage block.

usage: certreq.sh [-dhV] [-u username] [-p password] [-w tempdir] [-t template] [--cn CN] [--ca ]
version ${certreqversion}
 -d debug   Show debugging info, including parsed variables.
 -h usage   Show this usage block.
 -V version Show script version number.
 -u username User to connect via ntlm to CA. Can be "username" or "domain\\username"
 -p password
 -w workdir  Temp directory to work in. Default is a (mktemp -d).
 -t template Template to request from CA. Default is "ConfigMgrLinuxClientCertificate"
 --cn        CN to request. Default is the \$( hostname -f )
 --ca        CA hostname or base URL. Example: ca2.example.com
Return values under 1000: A non-zero value is the sum of the items listed here:
 0 Everything worked
 1 Cert file is still a CSR
 2 Cert file is html, probably due to permissions/credentials issue
 4 Return code of curl statement that saves cert file is non-zero
 8 Cert file does not contain whole certificate
16 Cert does not contain an issuer
Return values above 1000:
1001 Help or version info displayed
1002 Count or type of flaglessvals is incorrect
1003 Incorrect OS type
1004 Unable to find dependency
1005 Not run as root or sudo

All the magic happens at line 239, the main loop. These blocks perform the different web requests, and are the real meat of this script.

Block GENERATE PRIVATE KEY makes the csr and saves in to the file that will eventually hold the cert.

   # GENERATE PRIVATE KEY
   openssl req -new -nodes \
      -out "${CERTREQ_WORKDIR}/${CERTREQ_CNPARAM}.crt" \
      -keyout "${CERTREQ_WORKDIR}/${CERTREQ_CNPARAM}.key" \
      -subj "${CERTREQ_SUBJECT}"
   CERT="$( cat "${CERTREQ_WORKDIR}/${CERTREQ_CNPARAM}.crt" | tr -d '\n\r' )"
   DATA="Mode=newreq&CertRequest=${CERT}&C&TargetStoreFlags=0&SaveCert=yes"
   CERT="$( echo ${CERT} | sed -e 's/+/%2B/g' | tr -s ' ' '+' )"
   CERTATTRIB="CertificateTemplate:${CERTREQ_TEMPLATE}"

SUBMIT CERTIFICATE SIGNING REQUEST submits the CSR to the website

   # SUBMIT CERTIFICATE SIGNING REQUEST
   OUTPUTLINK="$( curl -k -u "${CERTREQ_USER}:${CERTREQ_PASS}" --ntlm \
      "${CERTREQ_CA}/certsrv/certfnsh.asp" \
      -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
      -H 'Accept-Encoding: gzip, deflate' \
      -H 'Accept-Language: en-US,en;q=0.5' \
      -H 'Connection: keep-alive' \
      -H "Host: ${CERTREQ_CAHOST}" \
      -H "Referer: ${CERTREQ_CA}/certsrv/certrqxt.asp" \
      -H 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko' \
      -H 'Content-Type: application/x-www-form-urlencoded' \
      --data "Mode=newreq&CertRequest=${CERT}&CertAttrib=${CERTATTRIB}&TargetStoreFlags=0&SaveCert=yes&ThumbPrint=" | grep -A 1 'function handleGetCert() {' | tail -n 1 | cut -d '"' -f 2 )"
   CERTLINK="${CERTREQ_CA}/certsrv/${OUTPUTLINK}"

FETCH SIGNED CERTIFICATE downloads the cert that the previous page links to.

   # FETCH SIGNED CERTIFICATE
   curl -k -u "${CERTREQ_USER}:${CERTREQ_PASS}" --ntlm $CERTLINK \
      -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
      -H 'Accept-Encoding: gzip, deflate' \
      -H 'Accept-Language: en-US,en;q=0.5' \
      -H 'Connection: keep-alive' \
      -H "Host: ${CERTREQ_CAHOST}" \
      -H "Referer: ${CERTREQ_CA}/certsrv/certrqxt.asp" \
      -H 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko' \
      -H 'Content-Type: application/x-www-form-urlencoded' > "${CERTREQ_WORKDIR}/${CERTREQ_CNPARAM}.crt"
   finaloutput=$?

My additions to this secret sauce start with GET NUMBER OF CURRENT CA CERT. I needed the cert chain, so I automated fetching it from the server.
You have to find out how many different CA certs are being offered by this server, and then use the latest.

   # GET NUMBER OF CURRENT CA CERT
   RESPONSE="$( curl -s -k -u "${CERTREQ_USER}:${CERTREQ_PASS}" --ntlm \
      "${CERTREQ_CA}/certsrv/certcarc.asp" \
      -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
      -H 'Accept-Encoding: gzip, deflate' \
      -H 'Accept-Language: en-US,en;q=0.5' \
      -H 'Connection: keep-alive' \
      -H "Host: ${CERTREQ_CAHOST}" \
      -H "Referer: ${CERTREQ_CA}/certsrv/certrqxt.asp" \
      -H 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko' \
      -H 'Content-Type: application/x-www-form-urlencoded' )"
   CURRENTNUM="$( echo "${RESPONSE}" | grep -cE 'Option' )"

   # GET LATEST CA CERT CHAIN
   CURRENT_P7B="$( curl -s -k -u "${CERTREQ_USER}:${CERTREQ_PASS}" --ntlm \
      "${CERTREQ_CA}/certsrv/certnew.p7b?ReqID=CACert&Renewal=${CURRENTNUM}" \
      -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
      -H 'Accept-Encoding: gzip, deflate' \
      -H 'Accept-Language: en-US,en;q=0.5' \
      -H 'Connection: keep-alive' \
      -H "Host: ${CERTREQ_CAHOST}" \
      -H "Referer: ${CERTREQ_CA}/certsrv/certrqxt.asp" \
      -H 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko' \
      -H 'Content-Type: application/x-www-form-urlencoded' )"

   # CONVERT TO PEM
   echo "${CURRENT_P7B}" | openssl pkcs7 -print_certs -out "${CERTREQ_TEMPFILE}"

I like having the domain name in the filename, so this last part renames the cert chain.

   # RENAME TO PROPER FILENAME
   # will read only the first cert, so get domain of issuer of it.
   CA_DOMAIN="$( openssl x509 -in "${CERTREQ_TEMPFILE}" -noout -issuer 2>&1 | sed -r -e 's/^.*CN=[A-Za-z0-9]+\.//;' )"
   CHAIN_FILE="chain-${CA_DOMAIN}.crt"
   mv -f "${CERTREQ_TEMPFILE}" "${CERTREQ_WORKDIR}/${CHAIN_FILE}" 1>/dev/null 2>&1

The ansible role

I needed this task deployed to my whole environment, so I rolled it into an ansible role saved to gitlab and also added another feature, where it converts the generated cert files into a pcks12 (pfx) file for a specific application’s need.

References

Weblinks

  1. https://technet.microsoft.com/en-us/library/dn296456(v=ws.11).aspx
  2. https://serverfault.com/questions/538270/how-to-submit-certificate-request-from-red-hat-to-windows-ca
  3. https://stackoverflow.com/questions/31283476/submitting-base64-csr-to-a-microsoft-ca-via-curl/39722983#39722983
  4. https://gitlab.com/bgstack15/certreq/blob/master/files/certreq.sh
  5. https://gitlab.com/bgstack15/certreq
  6. Manipulating ssl certificates

Generate certificate with SubjectAltName attributes in FreeIPA

Overview

Last updated 2018-05-17

If you want to serve webpages with ssl certificates that have Subject Alternative Names, and you use FreeIPA, you will need to take a few steps to make this possible. If you got to this page, you probably already know the importance of SAN on a cert.

This document will demonstrate how to get IPA to sign a certificate that has the ever-important SubjectAltName.

Example environment

Freeipa domain is at ipa.example.com

Host storage1.ipa.example.com is serving https, and I want to also serve on other domain names:

secondary.domain.com
http://www.ipa.example.com
http://www.example.com

You don’t even need to have all the SANs in the same domain!

Generate certificate with SAN in freeipa

Generate private key

openssl genrsa -aes256 -out /root/certs/https-storage1.ipa.example.com.key 2048

Use a simple passphrase you can remember.

Generate certificate signing request

Before you generate the csr, you will need to modify the default openssl.cnf file so it will make a csr with Subject Alternative Names.
In CentOS 7, that file is /etc/pki/tls/openssl.cnf.
In section [req] add line

req_extensions = v3_req

In section [ v3_req ] add lines (to add a new section as well)

subjectAltName = @alt_names

[alt_names]
DNS.1 = secondary.domain.com
DNS.2 = storage1.ipa.example.com
DNS.3 = www.ipa.example.com
DNS.4 = www.example.com

You can also include IP.1 = 192.168.1.1 entries.
On my CentOS 7 system, here is the diff:

# diff /etc/pki/tls/openssl.cnf /etc/pki/tls/openssl.cnf.2017-05-19.01 
126c126
< req_extensions = v3_req # The extensions to add to a certificate request --- > # req_extensions = v3_req # The extensions to add to a certificate request
225,232d224
< 
< subjectAltName = @alt_names
< 
< [alt_names]
< DNS.1 = secondary.domain.com
< DNS.2 = storage1.ipa.example.com
< DNS.3 = www.ipa.example.com
< DNS.4 = www.example.com

Reference: http://apetec.com/support/GenerateSAN-CSR.htm
Now generate the csr.

# openssl req -new -key /root/certs/https-storage1.ipa.example.com.key -out /root/certs/https-storage1.ipa.example.com.csr
Enter pass phrase for /root/certs/https-storage1.ipa.example.com.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:US
State or Province Name (full name) []:Some State
Locality Name (eg, city) [Default City]:Default City
Organization Name (eg, company) [Default Company Ltd]:Example.com
Organizational Unit Name (eg, section) []:IT
Common Name (eg, your name or your server's hostname) []:storage1.ipa.example.com
Email Address []:bgstack15@gmail.com

Make entries in freeipa

To be able to sign a certificate in freeipa with whatever SANs you want, you need to have a host entry for each domain.
So manually create the hosts. You can force it; they are just dummy hosts.
Also manually create HTTP service entries for each of those hosts.

HTTP/secondary.domain.com@IPA.EXAMPLE.COM
HTTP/www.ipa.example.com@IPA.EXAMPLE.COM
HTTP/www.example.com@IPA.EXAMPLE.COM

I used the web interface for this, because it was easier for me. But everything in freeipa can be done with the cli; I simply haven’t done the research for how to make new host objects in FreeIPA on the command line yet.
Reference: https://www.redhat.com/archives/freeipa-users/2014-September/msg00267.html

Sign the certificate

In the web UI, you can navigate to Identity -> Services -> principal HTTP/storage1.ipa.example.com@IPA.EXAMPLE.COM.
Select the Actions button, and then New Certificate.
Paste the contents of the csr file.

Retrieve the certificate

In the web UI, under the section Service Certificate, select the Actions button -> Get certificate. You can copy the text and save it in the terminal.

References

Weblinks

  1. Generate CSR with SAN http://apetec.com/support/GenerateSAN-CSR.htm
  2. Generate each host and HTTP service https://www.redhat.com/archives/freeipa-users/2014-September/msg00267.html
  3. Generate CSR https://bgstack15.wordpress.com/2016/06/30/manipulating-ssl-certificates/