Hallo, dies ist ein Test.
PWD: /www/data-lst1/unixsoft/unixsoft/kaempfer/.public_html
Running in File Mode
Relative path: ./../../.././../../../lib/svc/method/identity-cert
Real path: /lib/svc/method/identity-cert
Zurück
#!/usr/bin/ksh # # Copyright (c) 2014, 2023, Oracle and/or its affiliates. # . /lib/svc/share/smf_include.sh # Key and cert files (extracted from SMF properties) CERT_LOCAL=/etc/certs/localhost CERT_CA_DIR=${CERT_LOCAL}/host-ca CERT_CA_HOST_ROOTKEY=${CERT_CA_DIR}/hostca.key CERT_CA_HOST_ROOTCRT=${CERT_CA_DIR}/hostca.crt CERT_HOST_KEY=${CERT_LOCAL}/host.key CERT_HOST_CRT=${CERT_LOCAL}/host.crt CERT_HOST_CSR=${CERT_LOCAL}/host.csr CERT_CA_HOST_O="O=Host Root CA" # Automated Install SMF variables PROP_CERT_FILE='certificate/cert/uri' PROP_CERT_KEY_FILE='certificate/cert/private_key/uri' PROP_CERT_DN='certificate/cert/subject' PROP_IPSUBJECTALTNAME='certificate/cert/add_ip_subject_altname' PROP_CERT_KEY_TYPE='certificate/cert/keytype' PROP_CERT_KEY_LEN='certificate/cert/keylen' PROP_CERT_HASH='certificate/cert/hash' PROP_CERT_LIFETIME='certificate/cert/lifetime' PROP_CERT_VALUE='certificate/cert/pem_value' PROP_KEY_VALUE='certificate/cert/private_key/pem_value' PROP_CA_VALUE='certificate/ca/pem_value' PROP_CA_KEY_TYPE='certificate/ca/keytype' PROP_CA_KEY_LEN='certificate/ca/keylen' PROP_CA_HASH='certificate/ca/hash' PROP_CA_LIFETIME='certificate/ca/lifetime' PROP_CA_VALUE='certificate/ca/pem_value' PROP_GENERATE='certificate/generate' PROP_GENERATE_CA='certificate/ca/generate' # Global SMF property values SMF_HOST_CRT=$(svcprop -p $PROP_CERT_FILE $SMF_FMRI 2>/dev/null) SMF_HOST_KEY=$(svcprop -p $PROP_CERT_KEY_FILE $SMF_FMRI 2>/dev/null) CERT_DN=$(svcprop -p $PROP_CERT_DN $SMF_FMRI 2>/dev/null) CERT_KEY_TYPE=$(svcprop -p $PROP_CERT_KEY_TYPE $SMF_FMRI 2>/dev/null) CERT_KEY_LEN=$(svcprop -p $PROP_CERT_KEY_LEN $SMF_FMRI 2>/dev/null) CERT_HASH=$(svcprop -p $PROP_CERT_HASH $SMF_FMRI 2>/dev/null) CERT_LIFETIME=$(svcprop -p $PROP_CERT_LIFETIME $SMF_FMRI 2>/dev/null) IPSUBJECTALTNAME=$(svcprop -p $PROP_IPSUBJECTALTNAME $SMF_FMRI 2> /dev/null) CA_KEY_TYPE=$(svcprop -p $PROP_CA_KEY_TYPE $SMF_FMRI 2>/dev/null) CA_KEY_LEN=$(svcprop -p $PROP_CA_KEY_LEN $SMF_FMRI 2>/dev/null) CA_HASH=$(svcprop -p $PROP_CA_HASH $SMF_FMRI 2>/dev/null) CA_LIFETIME=$(svcprop -p $PROP_CA_LIFETIME $SMF_FMRI 2>/dev/null) CA_PEM_VALUE=$(svcprop -p $PROP_CA_VALUE $SMF_FMRI 2>/dev/null) CERT_PEM_VALUE=$(svcprop -p $PROP_CERT_VALUE $SMF_FMRI 2>/dev/null) KEY_PEM_VALUE=$(svcprop -p $PROP_KEY_VALUE $SMF_FMRI 2>/dev/null) # Set to true manually or set below automatically for expired generated certs: GENERATE=$(svcprop -p $PROP_GENERATE $SMF_FMRI 2> /dev/null) GENERATE_CA=$(svcprop -p $PROP_GENERATE_CA $SMF_FMRI 2> /dev/null) DNS_STATE=$(svcs -Ho state svc:/network/dns/client:default) SUBJECT_ALTNAME="" typeset -A altnames # For deduplicating IP and DNS altnames function debug { if [ "$DEBUG" == "true" ]; then echo "DEBUG: $@" fi } # Wrap /usr/bin/host with a check on svc:/network/dns/client function dns_lookup { # If dns/client service is disabled don't use /usr/bin/host. # While we could check for "online" we don't want to assume # that it can't be in a degraded state or anything else that # SMF manages for dependencies. if [ "$DNS_STATE" == "disabled" ]; then return fi /usr/bin/host "$@" } # Store PEM file $1 into SMF property $2. function store_pem { typeset -r pem_file="$1" typeset -r prop="$2" if svccfg -s $SMF_FMRI setprop $prop = astring: "$(cat $pem_file)"; then debug "Stored $pem_file in $SMF_FMRI:$prop" else echo "Failed to store $pem_file in $SMF_FMRI:$prop" fi } # Extract SMF property $2 into PEM file $1. function extract_pem { typeset -r pem_file="$1" typeset -r tmp_pem_file=$(mktemp /tmp/identity-cert.XXXXXX) typeset -r prop="$2" typeset -r propval=$(svcprop -p $prop $SMF_FMRI) # We only want to attempt the replacement if the PEM file content is # actually going to change. # If the file needs replacing and root is immutable go into # the degraded state. echo "$propval" | sed -e 's/\\//g' > "${tmp_pem_file}" diff "${pem_file}" "${tmp_pem_file}" 2> /dev/null if [ $? -eq 0 ]; then debug "Existing $pem_file already contains SMF PEM content" rm -f ${tmp_pem_file} return fi if [[ ! -w ${CERT_LOCAL} ]]; then smf_method_exit ${SMF_EXIT_DEGRADED} cert_extract \ "${$CERT_LOCAL} read-only, unable to extract " "certificate ${pem_file}" fi debug "Extracting $prop into $pem_file" if [[ -f $pem_file ]]; then cp "$pem_file" "${pem_file}.old" fi mv "${tmp_pem_file}" "${pem_file}" } # # add_altname # Add the altname if it is not already present. # Uses an associative array index by the altname to deduplicate. function add_altname { if [[ -n ${altnames["$1"]} ]]; then return fi if [[ -z $SUBJECT_ALTNAME ]]; then SUBJECT_ALTNAME=$1 else SUBJECT_ALTNAME="${SUBJECT_ALTNAME},$1" fi altnames["$1"]=$1 } # # generate_ca # Generate the key and cert of the host CA and add it to the # set of local trusted CAs # function generate_ca { mkdir -p $CERT_CA_DIR typeset -r ca_subject="$CERT_CA_HOST_O, CN=$(hostname 2> /dev/null)" # Generate Root CA Key/Crt echo "Generating Host CA: subject=\"$ca_subject\"" ca_serial=$(od -An -N6 -x /dev/urandom | nawk '{print $1$2$3;}') if ! pktool gencert keystore=file format=pem serial=$ca_serial \ keyusage=keyCertSign,cRLSign outkey=${CERT_CA_HOST_ROOTKEY} \ keylen=${CA_KEY_LEN} keytype=${CA_KEY_TYPE} hash=${CA_HASH} \ outcert=${CERT_CA_HOST_ROOTCRT} lifetime=${CA_LIFETIME} \ subject="$ca_subject" ; then echo "Failed to generate Root CA Key/Certificate" exit ${SMF_EXIT_ERR_FATAL} fi # Add the host CA to the trusted cert list # note we don't need to restart ca-certificates service from here # since it has a restart_on dependency on this service. echo "Adding Host CA to trusted ca-certificates list" ln -sf $CERT_CA_HOST_ROOTCRT /etc/certs/CA/localhost-hostca.pem echo "Storing CA certificate and key in SMF properties" store_pem $CERT_CA_HOST_ROOTCRT $PROP_CA_VALUE echo "Disabling CA re-generation" svccfg -s $SMF_FMRI setprop $PROP_GENERATE = boolean: false } # # generate_cert_files # Ensure that CERT Key/Certificate files are in place. If not create a # default set. A customer will most likely choose to provide their # own specific CERT Key/Certificate files thus we only create them if # they do not exist. # # Args # None # Returns # 0 - CERT Key/Cert exists or have been created successfully # 1 - Failed to create Key/Cert # function generate_cert_files { typeset hostname typeset host typeset myfqdn typeset DN typeset ca_subject typeset ca_serial typeset cert_serial mkdir -p $CERT_LOCAL # Get hostname and FQDN hostname=$(hostname 2> /dev/null) if [[ -n $hostname ]] ; then if host=$(dns_lookup $hostname 2> /dev/null) ; then # Output format is 1 or more of one of the following: # "<fqdn> has address <address>" or "Name:\t<fqdn>" myfqdn=$(echo "$host" | \ nawk '/Name:/ {print $2; exit} /has address/ {print $1; exit}') fi else hostname="localhost" fi # DN comes from the service property or we use the CN=hostname/fqdn if [[ -n ${CERT_DN} ]]; then DN="${CERT_DN}" elif [[ -n ${myfqdn} ]]; then DN="CN=${myfqdn}" add_altname "DNS=$myfqdn" else DN="CN=${hostname}" fi # Add the short hostname as a DNS altname add_altname "DNS=$hostname" # Find the locally configured (but not dhcp or addrconf) addresses # and add the addresses and names they resolve to as altnames. # # We purposely provide a way to avoid adding IP address altnames # due to the reasons given in RFC 6125, particularly the NAT # issue and the fact that very few CAs will issue such a # certificate anyway. # However there are use cases where this is needed so by default # add all local IP addresses, but ignore anything that is loopback # or dhcp/addrconf or is a known link-local IPv4 address. # # Note that while getent would be easier to parse it might only give # an answer from local files so we need to use the host command to # force a DNS lookup. ipadm show-if -p -o class,ifname | \ while IFS=: read class ifname ; do [[ $class == "loopback" ]] && continue ipadm show-addr -p -o type,addr $ifname | \ while IFS=: read ift addr ; do if [ "$ift" == "dhcp" -o \ "$ift" == "addrconf" ] ; then continue; fi ipaddr=$(echo $addr | cut -d/ -f1) case $ipaddr in 169\.254\.*) continue;; esac if [[ $IPSUBJECTALTNAME == "true" ]]; then add_altname "IP=$ipaddr" fi # Add the subject altnames as per RFC 6125, # even if we had a DN in the SMF properties. if ! resname=$(dns_lookup $ipaddr 2>/dev/null) ; then continue fi resname=$(echo $resname | cut -d' ' -f5 | sed s/\.$//g) if [ -n "$resname" ]; then add_altname "DNS=$resname" fi done done # Generate host csr echo "Generating Host CSR: subject=\"$DN\" \c" echo "subjectaltName=\"$SUBJECT_ALTNAME\"" if ! pktool gencsr keystore=file format=pem keytype=${CERT_KEY_TYPE}\ hash=${CERT_HASH} keylen=${CERT_KEY_LEN} \ outkey=${CERT_HOST_KEY} outcsr=${CERT_HOST_CSR} \ eku=serverAuth,clientAuth subject=${DN} \ altname="$SUBJECT_ALTNAME" ; then echo "Failed to generate Server Key/Certificate Signing Request" exit ${SMF_EXIT_ERR_FATAL} fi # Sign host csr with host Root CA key/cert if [[ -r $CERT_CA_HOST_ROOTKEY ]]; then # The "odd" looking field separator for nawk is because the # openssl cli uses the same separator '=' for the selected # output fields as X.509 uses for the components of the DN. ca_subject="$(openssl x509 -issuer -nameopt RFC2253 -noout \ -in $CERT_CA_HOST_ROOTCRT | \ nawk -F'issuer= ' '{ print $2 }')" echo "Signing Host CSR with Host CA...\c" cd $CERT_CA_DIR cert_serial=$(od -An -N6 -x /dev/urandom|nawk '{print $1$2$3;}') if ! pktool signcsr keystore=file format=pem \ serial=$cert_serial \ csr=${CERT_HOST_CSR} signkey=${CERT_CA_HOST_ROOTKEY} \ outcert=${CERT_HOST_CRT} lifetime=${CERT_LIFETIME} \ eku=serverAuth,clientAuth issuer="${ca_subject}" ; then echo "Failed to generate Server Certificate" exit ${SMF_EXIT_ERR_FATAL} fi echo "Certificate generation complete" else echo "No Host CA present, CSR saved as $CERT_HOST_CSR" fi echo "Storing certificates in SMF properties" store_pem $CERT_HOST_CRT $PROP_CERT_VALUE store_pem $CERT_HOST_KEY $PROP_KEY_VALUE echo "Disabling re-generation" svccfg -s $SMF_FMRI setprop $PROP_GENERATE = boolean: false svccfg -s $SMF_FMRI refresh return $? } # # extract_cert_files # The certificate and/or private key is in the service properties as a PEM # file, just extract it out into the appropriate location. function extract_cert_files { # Must have at least a certificate and key if [[ -z $CERT_PEM_VALUE && -z $KEY_PEM_VALUE ]]; then return fi if [[ -z $CERT_PEM_VALUE || -z $KEY_PEM_VALUE ]]; then echo "Both $PROP_CERT_VALUE and $PROP_KEY_VALUE must be set" exit $SMF_EXIT_ERR_CONFIG fi debug "Extracting keys from SMF properties" extract_pem $CERT_HOST_CRT $PROP_CERT_VALUE extract_pem $CERT_HOST_KEY $PROP_KEY_VALUE # Extract CA PEM file, if any. if [[ -n $CA_PEM_VALUE ]]; then mkdir -p $CERT_CA_DIR extract_pem $CERT_CA_HOST_ROOTCRT $PROP_CA_VALUE fi } # # verify_smf_properties # Ensures specific SMF property values are set. # # Args # None # Returns # Nothing, Exits with SMF_EXIT_ERR_CONFIG # function verify_smf_properties { debug "Verifying SMF property consistency" if [[ $GENERATE == "true" ]]; then # Property "generate" cannot be true if unexpired certs exist. if [[ -n $CERT_PEM_VALUE && $EXPIRED == "false" ]]; then echo "$PROP_CERT_VALUE and $PROP_GENERATE both set\c" echo "and certificate has not expired" exit $SMF_EXIT_ERR_CONFIG elif [[ -n $KEY_PEM_VALUE && $EXPIRED == "false" ]]; then echo "$PROP_KEY_VALUE and $PROP_GENERATE both set\c" echo "and certificate has not expired" exit $SMF_EXIT_ERR_CONFIG fi fi if [[ -z ${SMF_HOST_CRT} ]]; then echo "CERT Certificate File '${PROP_CERT_FILE}' is not set" exit ${SMF_EXIT_ERR_CONFIG} elif [[ -z $SMF_HOST_KEY ]]; then echo "CERT Certificate Key File '${PROP_CERT_KEY_FILE}'" \ "is not set" exit ${SMF_EXIT_ERR_CONFIG} fi # If any one of the files specified in the SMF configuration are not # the default generated files, this means that an inconsistent # configuration exists in SMF. This isn't necessarily wrong but # other services might have an issue so we warn. if [[ ${SMF_HOST_KEY} != ${CERT_HOST_KEY} || \ ${SMF_HOST_CRT} != ${CERT_HOST_CRT} ]]; then echo "An inconsistent security configuration exists in SMF" echo "Either a file is missing or a custom value has been " \ "incorrectly specified in SMF" if [[ ${SMF_HOST_KEY} != ${CERT_HOST_KEY} ]]; then echo "SMF Property : ${PROP_CERT_KEY_FILE}" echo " Default Value : ${CERT_HOST_KEY}" echo " Custom Value : ${SMF_HOST_KEY}" fi if [[ ${SMF_HOST_CRT} != ${CERT_HOST_CRT} ]]; then echo "SMF Property : ${PROP_CERT_FILE}" echo " Default Value : ${CERT_HOST_CRT}" echo " Custom Value : ${SMF_HOST_CRT}" fi exit ${SMF_EXIT_ERR_CONFIG} fi debug "SMF properties OK" } # Remove the SMF identity service certs and keys but not the host CA. function remove_old_certs { if [[ -f $CERT_HOST_CRT ]]; then echo "Removing old certificate and key" rm -f "$CERT_HOST_KEY" "$CERT_HOST_CRT" "$CERT_HOST_CSR" fi } # Remove only the CA certificate and key. function remove_ca { if [[ -f $CERT_CA_HOST_ROOTCRT ]]; then echo "Removing Host CA certificate and key" rm -f "$CERT_CA_HOST_ROOTKEY" "$CERT_CA_HOST_ROOTCRT" fi } if [[ -z $SMF_FMRI ]]; then echo "$0: this script can only be invoked by smf(7)" exit $SMF_EXIT_ERR_NOSMF fi verify_smf_properties # Check if the certificate is present but expired. if [[ -n $CERT_PEM_VALUE ]]; then debug "Checking Host certificate validity dates." hostcert=$(svcprop -p $PROP_CERT_VALUE $SMF_FMRI |sed 's/\\//g') if ! expiredate=$(echo "$hostcert" | \ openssl x509 -checkend 0 -enddate -noout) ; then echo "Host certificate has expired: $expiredate". EXPIRED="true" else debug "Host certificate still valid" fi fi # Force host cert regeneration when it has expired and we have the CA key. if [[ $EXPIRED == "true" ]]; then if [[ -r $CERT_CA_HOST_ROOTKEY ]]; then echo "Forcing regeneration using existing CA" GENERATE="true" GENERATE_CA="false" fi fi if [[ $GENERATE == "true" ]]; then if [[ $EXPIRED == "true" ]]; then echo "Removing old certificate and preserving key" rm -f "$CERT_HOST_KEY" "$CERT_HOST_CRT" "$CERT_HOST_CSR" else echo "Removing old certificate and key" rm -f "$CERT_HOST_KEY" "$CERT_HOST_CRT" "$CERT_HOST_CSR" fi remove_old_certs if [[ "$GENERATE_CA" == "true" ]]; then remove_ca generate_ca fi generate_cert_files else extract_cert_files fi if [[ ! -f $CERT_HOST_CRT || ! -f $CERT_HOST_KEY ]]; then echo "Key and/or Certificate not present in $CERT_LOCAL" exit $SMF_EXIT_ERR_FATAL fi exit $SMF_EXIT_OK