OpenSolaris_b135/cmd/mms/mm/common/mmsssl.sh

#!/bin/sh
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
#
#
# MMS SSL Self-Signed Certificate Authority
#

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/sadm/bin:$PATH
LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH

umask 066 
PROG=`basename $0`


# Now setup directories
SSLDIR="/var/mms/ssl"
CADIR="$SSLDIR/ca"
PUBDIR="$SSLDIR/pub"
ROOT_CNF="$CADIR/mms_openssl.cnf"
CERTSDIR="$CADIR/certs"
DIR=

# DSA Parameters Prime Number Bit Length
PRIME_BITS=2048

# User
USER=""
MMS_USER="mms"

# Root files (CA)
SERIAL="$CADIR/serial"
INDEX="$CADIR/index.txt"
CRL="$PUBDIR/$MMS_USER""_crl.pem"
ROOT_CERT="$CADIR/$MMS_USER""_ca_cert.pem"
ROOT_KEY="$CADIR/$MMS_USER""_ca_key.pem"
PASSWD_FILE="$CADIR/$MMS_USER""_ca_pass"
ROOT_PEM="$CADIR/$MMS_USER""_ca.pem"
ROOT_CERT_PUB="$PUBDIR/$MMS_USER""_ca_cert.pem"
MMS_PEM="$PUBDIR/$MMS_USER.pem"
MMS_CERT="$PUBDIR/$MMS_USER""_cert.pem"
MMS_DH1024="$PUBDIR/$MMS_USER""_dh1024.pem"

root_user()
{
	user=`/bin/id | grep root | wc -l`
	if [ $user -eq 0 ]; then
		echo "Error, you must be root to run this script."
		exit 1
	fi
}

gen_password()
{
	pass_file="$1"

	echo
	echo "Generate private key password phrase"

	/bin/dd if=/dev/random bs=1 count=15 2>/dev/null | \
		openssl base64 > "$pass_file"
	if [ ! -f "$pass_file" ]; then
		exit 1
	fi
}

# setup mms as ca (certificate authority)
initialize()
{
	echo
	echo "Initialize certificate authority"

	# certificate serial number
	echo "01" > "$SERIAL"
	if [ ! -f "$SERIAL" ]; then
		exit 1
	fi

	# certificate database
	touch "$INDEX"
	if [ ! -f "$INDEX" ]; then
		exit 1
	fi

	# new certs dir
	mkdir $CERTSDIR
	if [ $? -ne 0 ]; then
		exit 1
	fi

	chmod 0700 $CERTSDIR
	if [ $? -ne 0 ]; then
		exit 1
	fi

	# ca random password phrase
	gen_password "$PASSWD_FILE"
}

# generate crl (certificate revocation list) file
update_crl()
{
	echo
	echo "Update CRL"

	cmd="openssl ca -gencrl -out $CRL -config $ROOT_CNF"
	cmd="$cmd -passin file:$PASSWD_FILE"
	echo $cmd
	$cmd
	if [ $? -ne 0 ]; then
		exit 1
	fi

	# publish the list, let everyone read the file
	chmod 0640 $CRL
	if [ $? -ne 0 ]; then
		exit 1
	fi

	# tell mm to reload updated crl
	svcadm refresh mms:mm > /dev/null 2>&1
}

# compute public shared prime number p and generator g
dh_pem()
{
	echo
	echo "Generate Diffie-Hellman parameters"

	cmd="openssl dhparam -check -5 1024 -out $MMS_DH1024 -outform PEM"
	echo $cmd
	$cmd
	if [ $? -ne 0 ]; then
		exit 1
	fi

	chmod 0600 $MMS_DH1024
	if [ $? -ne 0 ]; then
		exit 1
	fi
}

# rsa private key
rsa_key()
{
	rsa_key_file="$1"

	echo
	echo "Create RSA certificate with SHA-1 signature"

	cmd="openssl genrsa -out $rsa_key_file -des3"
	cmd="$cmd -passout file:$PASSWD_FILE"
	echo $cmd
	$cmd
	if [ $? -ne 0 ]; then
		exit 1
	fi
}

# generate self signed root certificate and private key
rsa_cert()
{
	echo
	echo "Generate self-signed certificate authority"

	unset -v OPENSSL_CONF
	# gen self signed ca certificate
	cmd="openssl req -x509 -newkey rsa:$PRIME_BITS -out $ROOT_CERT"
	cmd="$cmd -keyout $ROOT_KEY -sha1 -outform PEM"
	cmd="$cmd -passout file:$PASSWD_FILE"
	echo $cmd
	$cmd
	if [ $? -ne 0 ]; then
		exit 1
	fi

	chmod 0600 "$ROOT_CERT"
	if [ $? -ne 0 ]; then
		exit 1
	fi

	# mms_ca.pem
	cat $ROOT_CERT $ROOT_KEY > $ROOT_PEM
	if [ ! -f $ROOT_PEM ]; then
		exit 1
	fi

	# put ca certificate in public directory 
	cp $ROOT_CERT $ROOT_CERT_PUB
	if [ $? -ne 0 ]; then
		exit 1
	fi

	# let everyone read public ca certificate
	chmod 0440 $ROOT_CERT_PUB
	if [ $? -ne 0 ]; then
		exit 1
	fi

	# view certificate info
	openssl x509 -subject -issuer -noout -in $ROOT_CERT

	# initialize cert revocation list 
	update_crl
}

certificate_request()
{
	dir=$1
	mess=$2

	echo
	echo "Generate certificate request ($USER,$dir)"

	mkdir -p "$dir"
	if [ $? -ne 0 ]; then
		exit 1
	fi

	# user password phrase
	pass_file="$dir/$USER""_pass"
	gen_password "$pass_file"

	# filenames
	req="$dir/$USER""_req.pem"

	key="$dir/$USER""_key.pem"

	# use default openssl configuration for certificate request
	unset -v OPENSSL_CONF

	# generate certificate request
	cmd="openssl req -newkey rsa:$PRIME_BITS -keyout $key -keyform PEM"
	cmd="$cmd -out $req -outform PEM -sha1 -passout file:$pass_file"
	echo $cmd
	$cmd
	if [ $? -ne 0 ]; then
		exit 1
	fi
	if [ $mess -eq 1 ]; then
		echo
		echo
		echo
		echo "Certificate request:  $req"
		echo "Private key:          $key"
		echo "Private key password: $pass_file"
		echo
		echo "Email certificate request file to MMS CA for signing."
		echo
	fi
}

ca_sign()
{
	echo
	echo "Sign certificate request"

	# filenames
	req="$PUBDIR/$USER""_req.pem"

	cert="$PUBDIR/$USER""_cert.pem"

	key="$PUBDIR/$USER""_key.pem"

	root_cert=`basename $ROOT_CERT`

	# root signs client certificate request
	cmd="openssl ca -in $req -out $cert -notext -cert $ROOT_CERT"
	cmd="$cmd -config $ROOT_CNF -md sha1 -passin file:$PASSWD_FILE"
	echo $cmd
	$cmd
	if [ $? -ne 0 ]; then
		exit 1
	fi

	if [ -f $key ]; then
		# combine certificate, private key and public root certificate
		pem="$PUBDIR/$USER.pem"
		cat $cert $key $ROOT_CERT_PUB > $pem
		if [ $? -ne 0 ]; then
			rm -f $pem
			echo "Error, create $pem"
		else
			echo
			echo "The combined certificate, private key and CA certificate file\n$pem"
			echo
		fi
	else
		user_cert=`basename $cert`
		user_key=`basename $key`
		# remote user without access to ssl public directory
		echo
		echo "Use the distinguished name email address to deliver"
		echo "the following files to the user:"
		echo "\t$cert"
		echo "\t$ROOT_CERT_PUB"
		echo
		echo "Instruct the user to do the following:"
		echo "\tcat $user_cert $user_key $root_cert > $USER.pem"
		echo
	fi
}

# revoke client's certificate
revoke_certificate()
{
	echo "Revoke certificate"

	# filename
	cert="$PUBDIR/$USER""_cert.pem"

	# revoke certificate
	cmd="openssl ca -revoke $cert -config $ROOT_CNF"
	cmd="$cmd -passin file:$PASSWD_FILE"
	echo $cmd
	$cmd
	if [ $? -ne 0 ]; then
		exit 1
	fi

	# add revoked cert to the list
	update_crl
}

check_client()
{
	if [ -z "$USER" ]; then
		echo "Error, missing user name."
		exit 1
	fi
}

usage()
{
    echo "usage: mmsssl.sh [ ca | req | crl ] [-v] [-n]"
    echo
    echo "mmsssl.sh ca -c                           configure mms ca"
    echo "mmsssl.sh ca -s -u user_name              sign certificate request"
    echo "mmsssl.sh ca -r -u user_name              revoke certificate"
    echo "mmsssl.sh req -u user_name [-d path]      certificate request"
    echo "mmsssl.sh crl                             revoked certificate list"
    echo
    echo "Examples:"
    echo "1. Create the MMS CA and MM RSA certificates:"
    echo "\t% mmsssl.sh ca -c"
    echo "\tRun the command only once on the host where the MM will execute."
    echo "\tDiffie-Hellman (DH) parameters are generated." 
    echo "\tYou will enter a DN (Distinguished Name) once for the CA and"
    echo "\tonce for the MM certificate. You will sign the MM certificate"
    echo "\tand commit the request."
    echo
    echo "2. MMS user certificate request:"
    echo "\t% mmsssl.sh req -u JohnQPublic"
    echo "\tEmail the JohnQPublic_req.pem to the MMS CA for signing." 
    echo
    echo "3. MMS CA signs user certificate request:"
    echo "\t% cp JohnQPublic_req.pem \\"
    echo "\t$PUBDIR/JohnQPublic_req.pem"
    echo "\tCopy certificate request into the MMS CA for signing."
    echo "\t% mmsssl.sh ca -s -u JohnQPublic"
    echo "\tYou will sign the MM certificate and commit the request."
    echo "\tEmail the JohnQPublic_cert.pem and mms_ca_cert.pem "\
					"files to the user."
    echo
    echo "4. MMS user creates single PEM file for MMS:"
    echo "\t% cat JohnQPublic_cert.pem JohnQPublic_key.pem \\"
    echo "\tmms_ca_cert.pem > JohnQPublic.pem"
    echo
    echo "5. MMS CA revokes user certificate:"
    echo "\t% mmsssl.sh ca -r -u JohnQPublic"
    echo "\tThe revoked certificate is added to the file"
    echo "\t$PUBDIR/mms_crl.pem"
    echo
    echo "6. MMS CA reviews CRL (Certificate Revocation List):"
    echo "\t% mmsssl.sh crl"
    echo "\tLists revoked certificate serial numbers."
    echo
    echo "Notes:"
    echo "1. user_name is one word i.e. John Q. Public is JohnQPublic"
    echo "2. one-way authentication is where only the server is configured"
    echo "   with a RSA certificate."
    echo "3. two-way authentication is when the server and client both have"
    echo "   a RSA certificate." 
    echo "4. MMS supports both one-way and two-way authentication."
    echo "5. The MMS CA can use a certificate request made by a tool"
    echo "   other than this script."
    echo "6. The crl.pem file contains the CRL for this MMS CA."
    echo "7. The MM, Watcher, LM (Library Manager) and DM (Drive Manager)"
    echo "   can use the same certificate."
    echo
    exit 2
}

#
# Main
#

if [ $# -eq 0 ]; then
	usage
fi

choice=$1
oper=""
shift
found=0
while getopts "csru:d:" opt; do
	found=0
	case $opt in
	c)
		# setup mms ca
		oper="configure"
		found=1
		;;
	s)	
		# Create Signed Certificate on this host.
		#
		# On remote hosts its a two step process:
		#	1. request certificate
		#	2. CA sign's certificate  
		oper="sign"
		found=1
		;;
	r)	
		# Revoke Certificate
		#
		# Update the MM CA CRL and put on all remote hosts
		# especially if you have one MM CA for multiple MMs.
		oper="revoke"
		found=1
		;;
	u)
		# User Name
		USER="$OPTARG"
		found=1
		;;
	d)
		# User directory
		DIR="$OPTARG"
		found=1
		;;
	esac

	if [ $found -eq 0 ]; then
		usage
	fi
done

case $choice in
ca)
	# setup non-root MMS client in /etc
	OPENSSL_CONF="$ROOT_CNF"
	HOME="$CADIR"
	root_user
	case $oper in
	configure)
		# setup MMS CA
		root_user
		initialize
		dh_pem
		rsa_cert

		# sign mms certificate request 
		USER=$MMS_USER
		certificate_request "$PUBDIR" 0
		ca_sign
		echo "Done"
		;;

	sign)	
		# sign certificate request
		check_client
		ca_sign
		echo "Done"
		;;

	revoke)	
		if [ -z "$USER" ]; then
			echo "Error, missing client user name."
			exit 1
		fi

		revoke_certificate	
		echo "Done"
		;;

	*)	usage
		;;
	esac
	;;

req)
	# certificate request
	check_client
	if [ "$DIR" = "" ]; then
		DIR="$HOME/mms"
	fi
	certificate_request "$DIR" 1
	echo "Done"
	;;

crl)
	# show certificate revocation list
	crl=$CRL
	root_cert=$ROOT_CERT
	openssl crl -in $crl -text -noout
	openssl crl -in $crl -noout -CAfile $root_cert
	echo "Done"
	;;

*)	usage
	;;
esac

exit 0