-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathca-create-cert
More file actions
executable file
·192 lines (176 loc) · 7.51 KB
/
ca-create-cert
File metadata and controls
executable file
·192 lines (176 loc) · 7.51 KB
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/bin/bash
set -e
source $(dirname $(readlink -f $0))/../lib/ca-functions
ALT_NAMES=()
QUALIFY=1
CNF_ONLY=0
CSR_ONLY=0
CRT_ONLY=0
MAKE_P12=0
# XXX: in the ca_extension_policy section of ca-config.tpl it states that the
# C= and O= DN values in a CSR have to match those of the CA
# should we have options here to change them when it will cause breakage?
usage() {
cat <<__EOT__
Usage:
tiny-ca new [options] <common name>
Options:
-h, --help Print this helpful message!
-c, --encrypt Encrypt certificate private key with Triple-DES
-f, --config FILE Use config file instead of $CONFFILE
-t, --type TYPE Certificate type: "server" (default), "client" or "user"
-d, --days DAYS Certificate valid for DAYS days instead of CA_CRT_DAYS
-b, --bits BITS Generate a BITS bit certificate instead of CA_CRT_BITS
-n, --alt-name NAME Alternative host name (can be provided multiple times)
-i, --ip IP ADDRESS IP addresses to include in the certificate
-p, --pkcs12 Create PKCS#12 certificate archive from generated cert
-q, --no-qualify Don't qualify short (dotless) names with CA_DOMAIN
-r, --req-only Only generate CSR, don't sign it
-s, --sign-only Only sign certificate, requires CSR in place
-x, --cnf-only Only generate templates, do not create CSR or sign CRT
--country Certificate DN -- C
--state Certificate DN -- ST
--location Certificate DN -- L
--org Certificate DN -- O
--ounit Certificate DN -- OU
--email Certificate DN -- E
--comment Certificate nsComment field
__EOT__
}
short="hcf:t:d:b:n:i:pqrsx"
long="help,encrypt,config:,type:,days:,bits:,alt-name:,ip:"
long="$long,pkcs12,no-qualify,req-only,sign-only,cnf-only"
long="$long,country:,state:,location:,org:,ounit:,email:,comment:"
opts=$( getopt -o "$short" -l "$long" -n "$PROGNAME" -- "$@" )
if [ 0 -ne $? ]; then echo; usage; exit 1; fi
eval set -- "$opts";
while :; do
case "$1" in
-h|--help) usage; exit 0;;
-c|--encrypt) CRYPTKEY=""; shift;;
-f|--config) shift; CONFFILE="$1"; CONFFILECLI=1; shift;;
-t|--type) shift; USER_CA_CRT_TYPE="$1"; shift;;
-d|--days) shift; USER_CA_CRT_DAYS="$1"; shift;;
-b|--bits) shift; USER_CA_CRT_BITS="$1"; shift;;
-n|--alt-name) shift; ALT_NAMES+=("$1"); shift;;
-i|--ip) shift; ALT_IPS+=("$1"); shift;;
-p|--pkcs12) MAKE_P12=1; shift;;
-q|--no-qualify) QUALIFY=0; shift;;
-r|--req-only) CSR_ONLY=1; shift;;
-s|--sign-only) CRT_ONLY=1; shift;;
-x|--cnf-only) CNF_ONLY=1; shift;;
--country) shift; USER_CA_CRT_C="$1"; shift;;
--state) shift; USER_CA_CRT_ST="$1"; shift;;
--location) shift; USER_CA_CRT_L="$1"; shift;;
--org) shift; USER_CA_CRT_O="$1"; shift;;
--ounit) shift; USER_CA_CRT_OU="$1"; shift;;
--email) shift; USER_CA_CRT_E="$1"; shift;;
--comment) shift; USER_CA_CRT_COMMENT="$1"; shift;;
--) shift; break;;
*) echo "Unknown value '$1'"; exit 1;;
esac
done
# load up the configuration file
ca_load_conf
# This must be provided on the command line. There's no point setting a
# "default" certificate CN in the config, it should be different every time.
CA_CRT_CN="$1"
# parameter checking fun -- we need a type and a cn (either user or host name)
if [ -z "$CA_CRT_CN" ]; then
error "The host or username parameter is mandatory!"
fi
if [ 1 -eq "$CSR_ONLY" -a 1 -eq "$CRT_ONLY" ]; then
error "Options --csr-only and --crt-only are mutually exclusive."
fi
if [ "$CA_CRT_TYPE" = "user" ]; then
# append @$CA_DOMAIN to user CN if it's not already there and -q not set
if [ 1 -eq "$QUALIFY" -a "${CA_CRT_CN%%@*}" = "$CA_CRT_CN" ]; then
CA_CRT_CN="$CA_CRT_CN@$CA_DOMAIN";
fi
else
# fully qualify server or client CN with $CA_DOMAIN if it's not already
if [ 1 -eq "$QUALIFY" -a "${CA_CRT_CN%%.*}" = "$CA_CRT_CN" ]; then
# however we may also want the unqualified one as an alt-name
ALT_NAMES+=("$CA_CRT_CN")
CA_CRT_CN="$CA_CRT_CN.$CA_DOMAIN"
fi
fi
CNF_NAME=$( echo -n "$CA_CRT_CN" | tr -c '[:alnum:]@-' _ )".$CA_CRT_TYPE";
# if they've provided a comment, reformat it correctly
if [ -n "$CA_CRT_COMMENT" ]; then
CA_CRT_COMMENT="$( tr -d\" <<< $CA_CRT_COMMENT )"
CA_CRT_COMMENT="nsComment = \"$CA_CRT_COMMENT\"\n"
else
CA_CRT_COMMENT=""
fi
CA_CRT_ALT_NAMES=""
# generate a list of alternative DNS names for server or client certificates
if [ "$CA_CRT_TYPE" != "user" ]; then
i=1
for ALT_NAME in "$CA_CRT_CN" "${ALT_NAMES[@]}"; do
# also fully-qualify unqualified alt-names too (see below)
# NOTE: except when it's the previously-fully-qualified CN...
# XXX: maybe we should uniq the alt-names? hmm.
if [ 1 -eq "$QUALIFY" -a "${ALT_NAME%%.*}" = "$ALT_NAME" \
-a "${CA_CRT_CN%%.*}" != "$ALT_NAME" ]; then
CA_CRT_ALT_NAMES="${CA_CRT_ALT_NAMES}DNS.$i=$ALT_NAME.$CA_DOMAIN\n"
i=$(( $i+1 ))
fi
CA_CRT_ALT_NAMES="${CA_CRT_ALT_NAMES}DNS.$i=$ALT_NAME\n"
i=$(( $i+1 ))
done
p=1
for ALT_IP in "${ALT_IPS[@]}"; do
# add ips as IP.x
CA_CRT_ALT_NAMES="${CA_CRT_ALT_NAMES}IP.$p=$ALT_IP\n"
p=$(( $p+1 ))
done
fi
if [ 1 -ne "$CRT_ONLY" ]; then
if [ 1 -eq "$CNF_ONLY" -o "$CSR_ONLY" -eq "$CNF_ONLY" ]; then
# dirty logic here that probably needs commenting!
# generate a *new* certificate request configuration if...
# a) --cnf-only is set, i.e. we only want to generate a config
# b) both --cnf-only and --csr-only are unset, i.e.
# we're just generating a csr/crt as per usual
# c) both --cnf-only and --csr-only are set, i.e.
# we're just generating the config and not the csr itself
ca_template "req-config" "$CA_HOME/cnf/$CNF_NAME.req.cnf"
fi
if [ 1 -ne "$CNF_ONLY" ]; then
if [ ! -f "$CA_HOME/cnf/$CNF_NAME.req.cnf" ]; then
error "Couldn't find CSR config $CA_HOME/cnf/$CNF_NAME.req.cnf!"
fi
# the above logic means that if you pass --csr-only but not
# --cnf-only, you can re-use a pre-existing config to generate
# a new csr, should you wish to do so...
openssl req -new $CRYPTKEY -config "$CA_HOME/cnf/$CNF_NAME.req.cnf" \
-keyout "$CA_HOME/key/$CNF_NAME.key" \
-out "$CA_HOME/csr/$CNF_NAME.csr"
fi
fi
if [ 1 -ne "$CSR_ONLY" ]; then
if [ 1 -eq "$CNF_ONLY" -o "$CRT_ONLY" -eq "$CNF_ONLY" ]; then
# same logic above applies here, but for generating the extensions
# configuration file and signed certificate instead
ca_template "$CA_CRT_TYPE-ext" "$CA_HOME/cnf/$CNF_NAME.ext.cnf"
fi
if [ 1 -ne "$CNF_ONLY" ]; then
# ensure relevant files are in place before continuing...
if [ ! -f "$CA_HOME/csr/$CNF_NAME.csr" ]; then
error "CSR not present in $CA_HOME/csr/$CNF_NAME.csr"
fi
if [ ! -f "$CA_HOME/cnf/$CNF_NAME.ext.cnf" ]; then
error "Couldn't find extensions in $CA_HOME/cnf/$CNF_NAME.ext.cnf"
fi
openssl ca -config "$CA_HOME/cnf/$CA_NAME.ca.cnf" \
-days "$CA_CRT_DAYS" \
-md "$CA_DEFAULT_MD" \
-extfile "$CA_HOME/cnf/$CNF_NAME.ext.cnf" -batch \
-out "$CA_HOME/crt/$CNF_NAME.crt" \
-in "$CA_HOME/csr/$CNF_NAME.csr"
fi
fi
if [ 1 -eq "$MAKE_P12" ]; then
ca_gen_p12 "$CNF_NAME"
fi