forked from cgzones/easy-ca
-
Notifications
You must be signed in to change notification settings - Fork 11
/
sign-csr
executable file
·171 lines (140 loc) · 5.79 KB
/
sign-csr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/env bash
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# Derek Moore <[email protected]>
# Christian Göttsche <[email protected]>
# Tom Bereknyei <[email protected]>
set -eu
set -o pipefail
umask 0077
BIN_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source "${BIN_DIR}/functions"
source "${BIN_DIR}/defaults.conf"
usage() {
echo "Usage: $0 -c CSR_PATH [-F NAME]"
echo "Signs a client certificate located at CSR_PATH"
echo
echo "Options:"
echo " -c CSR_PATH Path to client certificate request"
echo
echo " -s Request is a server [default is client]"
echo
echo " -m CSR_CERT_MAIL Email address to use in client certificate request"
echo " Useful when using ykman which doesn't use email"
echo
echo " -F NAME Force to use custom SAFE_NAME"
echo " Useful for name clahses, use with caution"
echo
}
if [ ! -f ca/ca.crt ]; then
echo -e "$ERR Must be run inside a CA directory!"
exit 2
fi
CSR_PATH=
CSR_NAME=
CSR_TYPE="clients"
while getopts c:sF:m:h FLAG; do
case $FLAG in
c) CSR_PATH=${OPTARG} ;;
s) CSR_TYPE="server" ;;
F) CSR_NAME=${OPTARG} ;;
m) CSR_CERT_MAIL=${OPTARG} ;;
h) echo -e -n "$SUCC " && usage && exit 0 ;;
*) echo -e -n "$ERR " && usage && exit 2 ;;
esac
done
if [ $OPTIND -le $# ]; then
echo -e -n "$ERR " && usage && exit 2
elif [ "$CSR_PATH" = "" ]; then
echo -e -n "$ERR " && usage && exit 1
fi
openssl req -text -noout -verify -in "$CSR_PATH"
export CSR_SUBJ=$(openssl req -utf8 -in "$CSR_PATH" -noout -subject -nameopt multiline)
export CSR_CERT_CN=$(echo "$CSR_SUBJ" | grep -P '^\s+commonName' | cut -d '=' -f 2- | sed -e 's/^[[:space:]]*//')
if [ -z "$CSR_CERT_CN" ]; then
echo -e "$ERR No name supplied in request, exiting." >&2
exit 1
fi
if [ "$CSR_TYPE" = clients ]; then
export CSR_CERT_MAIL=${CSR_CERT_MAIL:-$(echo "$CSR_SUBJ" | grep -P '^\s+emailAddress' | cut -d '=' -f 2- | sed -e 's/^[[:space:]]*//')}
if [ -z "$CSR_CERT_MAIL" ]; then
echo -e "$ERR No email address supplied in request, exiting." >&2
exit 1
fi
elif [ "$CSR_TYPE" = server ]; then
# Retrieve the SAN by matching, grabbing the next line in the -text output, printing and quitting
CSR_CERT_SAN=$(openssl req -utf8 -in "$CSR_PATH" -noout -text | sed -n '/^[[:space:]]*X509v3 Subject Alternative Name:[[:space:]]*$/ {n;p;q}')
if [ -z "$CSR_CERT_SAN" ]; then
CSR_CERT_SAN="DNS:$CSR_CERT_CN"
fi
fi
if [ -n "$CSR_NAME" ]; then
SAFE_NAME=$(echo "$CSR_NAME" | sed 's/\*/star/g' | sed 's/[^A-Za-z0-9-]/-/g')
else
SAFE_NAME=$(echo "$CSR_CERT_CN" | sed 's/\*/star/g' | sed 's/[^A-Za-z0-9-]/-/g')
fi
if [ -f "certs/$CSR_TYPE/$SAFE_NAME/$SAFE_NAME.crt" ]; then
echo -e "$ERR Certificate already exist for '$CSR_CERT_CN' ($SAFE_NAME), exiting." >&2
exit 1
fi
export SAN="${CSR_CERT_SAN-email:$CSR_CERT_MAIL}"
if [ "$CSR_TYPE" = clients ]; then
echo -e "$NOTE Signing client CSR for '$CSR_CERT_CN' with email address '$CSR_CERT_MAIL'" >&2
elif [ "$CSR_TYPE" = server ]; then
echo -e "$NOTE Signing server CSR for '$CSR_CERT_CN' with CN '$CSR_CERT_CN' and SANs '$SAN'" >&2
fi
pushd "${BIN_DIR}/.." > /dev/null
echo
if [ -n "$CA_ENABLE_ENGINE" ]; then
echo -e "$NOTE Your CA key is on PKCS11 device, enter PIN." >&2
fi
PASS=`ask -s "$INPUT Enter passphrase for signing CA key: " CA_SIGN_PASS_DEFAULT "${SIGN_PASS:-""}"`
echo >&2
export CA_PASS="${PASS}"
openssl_engine_cmd='
-engine pkcs11
-inform engine
-in pkcs11:object=SIGN%20key'
openssl rsa \
${CA_ENABLE_ENGINE:+$openssl_engine_cmd} \
$( [ -z $CA_ENABLE_ENGINE ] && echo "-check -in ca/private/ca.key") \
-noout \
-passin env:CA_PASS
echo -e "$NOTE Creating $CSR_TYPE directory certs/$CSR_TYPE/$SAFE_NAME" >&2
mkdir -p "certs/$CSR_TYPE/$SAFE_NAME"
# Generate the cert openssl config
export CA_USERNAME="$CSR_CERT_CN"
if [ "$CSR_TYPE" = clients ]; then
export CA_CERT_MAIL="$CSR_CERT_MAIL"
fi
cp --suffix ".old" -b -f -u "$CSR_PATH" "certs/$CSR_TYPE/$SAFE_NAME/$SAFE_NAME.csr"
template "$BIN_DIR/templates/$CSR_TYPE.tpl" "certs/$CSR_TYPE/$SAFE_NAME/$SAFE_NAME.conf"
openssl req -in "certs/$CSR_TYPE/$SAFE_NAME/$SAFE_NAME.csr" -pubkey \
-out "certs/$CSR_TYPE/$SAFE_NAME/$SAFE_NAME.pub"
ssh-keygen -f "certs/$CSR_TYPE/$SAFE_NAME/$SAFE_NAME.pub" -i -mPKCS8 \
| awk "{printf \$0;print \" ${SAFE_NAME}\"}" > "certs/$CSR_TYPE/$SAFE_NAME/$SAFE_NAME.ssh.pub"
echo -e "$NOTE Creating the certificate (overwriting C,ST,L,O,OU DN fields)." >&2
if [ "$CSR_TYPE" = clients ]; then
CERT_SUBJ="/C=${CA_CERT_C}/ST=${CA_CERT_ST}/L=${CA_CERT_L}/O=${CA_CERT_O}/OU=${CA_CERT_OU}/CN=${CA_USERNAME}/emailAddress=${CSR_CERT_MAIL}"
elif [ "$CSR_TYPE" = server ]; then
CERT_SUBJ="/C=${CA_CERT_C}/ST=${CA_CERT_ST}/L=${CA_CERT_L}/O=${CA_CERT_O}/OU=${CA_CERT_OU}/CN=${CSR_CERT_CN}"
fi
# Create the client certificate overwriting CSR values
openssl_engine_cmd="\
-engine pkcs11 \
-keyform engine \
-keyfile pkcs11:object=SIGN%20key"
openssl ca -batch -notext \
${CA_ENABLE_ENGINE:+$openssl_engine_cmd} \
-config ca/ca.conf \
-in "certs/$CSR_TYPE/$SAFE_NAME/$SAFE_NAME.csr" \
-out "certs/$CSR_TYPE/$SAFE_NAME/$SAFE_NAME.crt" \
-extensions ${CSR_TYPE}_ext \
-subj "$CERT_SUBJ" \
-passin env:CA_PASS
echo -e "$NOTE Verifying trusted chain" >&2
openssl verify -CAfile ca/chain.pem "certs/$CSR_TYPE/$SAFE_NAME/$SAFE_NAME.crt"
popd > /dev/null
unset CA_PASS
echo -e "$SUCC Client certificate for '$CSR_CERT_CN' created." >&2