]> git.proxmox.com Git - mirror_ovs.git/blame - utilities/ovs-pki.in
ofp-util: Set Packet In Format: Use prevailing OpenFlow version
[mirror_ovs.git] / utilities / ovs-pki.in
CommitLineData
064af421
BP
1#! /bin/sh
2
e0edde6f 3# Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
a14bc59f
BP
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at:
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
064af421
BP
17set -e
18
19pkidir='@PKIDIR@'
20command=
21prev=
22force=no
23batch=no
24log='@LOGDIR@/ovs-pki.log'
25keytype=rsa
26bits=2048
0f5ed573
EM
27
28# OS-specific compatibility routines
29case $(uname -s) in
30FreeBSD)
31 file_mod_epoch()
32 {
33 stat -r "$1" | awk '{print $10}'
34 }
35
36 file_mod_date()
37 {
38 stat -f '%Sm' "$1"
39 }
40
41 sha1sum()
42 {
43 sha1 "$@"
44 }
45 ;;
46*)
47 file_mod_epoch()
48 {
49 date -r "$1" +%s
50 }
51
52 file_mod_date()
53 {
54 date -r "$1"
55 }
56 ;;
57esac
58
064af421
BP
59for option; do
60 # This option-parsing mechanism borrowed from a Autoconf-generated
61 # configure script under the following license:
62
63 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
64 # 2002, 2003, 2004, 2005, 2006, 2009 Free Software Foundation, Inc.
65 # This configure script is free software; the Free Software Foundation
66 # gives unlimited permission to copy, distribute and modify it.
67
68 # If the previous option needs an argument, assign it.
69 if test -n "$prev"; then
70 eval $prev=\$option
71 prev=
72 continue
73 fi
74 case $option in
75 *=*) optarg=`expr "X$option" : '[^=]*=\(.*\)'` ;;
76 *) optarg=yes ;;
77 esac
78
79 case $dashdash$option in
80 --)
81 dashdash=yes ;;
82 -h|--help)
83 cat <<EOF
84ovs-pki, for managing a simple OpenFlow public key infrastructure
85usage: $0 [OPTION...] COMMAND [ARG...]
86
87The valid stand-alone commands and their arguments are:
88 init Initialize the PKI
89 req NAME Create new private key and certificate request
90 named NAME-privkey.pem and NAME-req.pem, resp.
91 sign NAME [TYPE] Sign switch certificate request NAME-req.pem,
92 producing certificate NAME-cert.pem
93 req+sign NAME [TYPE] Combine the above two steps, producing all three files.
94 verify NAME [TYPE] Checks that NAME-cert.pem is a valid TYPE certificate
95 fingerprint FILE Prints the fingerprint for FILE
96 self-sign NAME Sign NAME-req.pem with NAME-privkey.pem,
97 producing self-signed certificate NAME-cert.pem
064af421
BP
98Each TYPE above is a certificate type: 'switch' (default) or 'controller'.
99
100Options for 'init', 'req', and 'req+sign' only:
101 -k, --key=rsa|dsa Type of keys to use (default: rsa)
102 -B, --bits=NBITS Number of bits in keys (default: 2048). For DSA keys,
103 this has an effect only on 'init'.
104 -D, --dsaparam=FILE File with DSA parameters (DSA only)
105 (default: dsaparam.pem within PKI directory)
2562714a 106Options for use with the 'sign' command:
064af421
BP
107 -b, --batch Skip fingerprint verification
108Options that apply to any command:
109 -d, --dir=DIR Directory where the PKI is located
110 (default: $pkidir)
111 -f, --force Continue even if file or directory already exists
112 -l, --log=FILE Log openssl output to FILE (default: ovs-log.log)
113 -h, --help Print this usage message.
d3e565ce 114 -V, --version Display version information.
064af421
BP
115EOF
116 exit 0
117 ;;
d3e565ce
BP
118 -V|--version)
119 echo "ovs-pki (Open vSwitch) @VERSION@"
120 exit 0
121 ;;
064af421
BP
122 --di*=*)
123 pkidir=$optarg
124 ;;
125 --di*|-d)
126 prev=pkidir
127 ;;
128 --k*=*)
129 keytype=$optarg
130 ;;
131 --k*|-k)
132 prev=keytype
133 ;;
134 --bi*=*)
135 bits=$optarg
136 ;;
137 --bi*|-B)
138 prev=bits
139 ;;
140 --ds*=*)
141 dsaparam=$optarg
142 ;;
143 --ds*|-D)
144 prev=dsaparam
145 ;;
146 --l*=*)
147 log=$optarg
148 ;;
149 --l*|-l)
150 prev=log
151 ;;
152 --force|-f)
153 force=yes
154 ;;
155 --ba*|-b)
156 batch=yes
157 ;;
158 -*)
159 echo "unrecognized option $option" >&2
160 exit 1
161 ;;
162 *)
163 if test -z "$command"; then
164 command=$option
165 elif test -z "${arg1+set}"; then
166 arg1=$option
167 elif test -z "${arg2+set}"; then
168 arg2=$option
169 else
170 echo "$option: only two arguments may be specified" >&2
171 exit 1
172 fi
173 ;;
174 esac
175 shift
176done
177if test -n "$prev"; then
178 option=--`echo $prev | sed 's/_/-/g'`
179 { echo "$as_me: error: missing argument to $option" >&2
180 { (exit 1); exit 1; }; }
181fi
182if test -z "$command"; then
183 echo "$0: missing command name; use --help for help" >&2
184 exit 1
185fi
186if test "$keytype" != rsa && test "$keytype" != dsa; then
7cdc630f 187 echo "$0: argument to -k or --key must be rsa or dsa" >&2
064af421
BP
188 exit 1
189fi
190if test "$bits" -lt 1024; then
7cdc630f 191 echo "$0: argument to -B or --bits must be at least 1024" >&2
064af421
BP
192 exit 1
193fi
194if test -z "$dsaparam"; then
195 dsaparam=$pkidir/dsaparam.pem
196fi
197case $log in
198 /*) ;;
37d03458 199 *) log=`pwd`/$log ;;
064af421
BP
200esac
201
ccc9fc5a
BP
202logdir=$(dirname "$log")
203if test ! -d "$logdir"; then
204 mkdir -p -m755 "$logdir" 2>/dev/null || true
205 if test ! -d "$logdir"; then
206 echo "$0: log directory $logdir does not exist and cannot be created" >&2
207 exit 1
208 fi
209fi
210
064af421
BP
211if test "$command" = "init"; then
212 if test -e "$pkidir" && test "$force" != "yes"; then
213 echo "$0: $pkidir already exists and --force not specified" >&2
214 exit 1
215 fi
216
217 if test ! -d "$pkidir"; then
218 mkdir -p "$pkidir"
219 fi
220 cd "$pkidir"
221 exec 3>>$log
222
223 if test $keytype = dsa && test ! -e dsaparam.pem; then
224 echo "Generating DSA parameters, please wait..." >&2
225 openssl dsaparam -out dsaparam.pem $bits 1>&3 2>&3
226 fi
227
a20d2466
JP
228 # Get the current date to add some uniqueness to this certificate
229 curr_date=`date +"%Y %b %d %T"`
230
064af421
BP
231 # Create the CAs.
232 for ca in controllerca switchca; do
233 echo "Creating $ca..." >&2
37d03458 234 oldpwd=`pwd`
064af421
BP
235 mkdir -p $ca
236 cd $ca
237
238 mkdir -p certs crl newcerts
239 mkdir -p -m 0700 private
064af421
BP
240 touch index.txt
241 test -e crlnumber || echo 01 > crlnumber
242 test -e serial || echo 01 > serial
243
244 # Put DSA parameters in directory.
245 if test $keytype = dsa && test ! -e dsaparam.pem; then
246 cp ../dsaparam.pem .
247 fi
248
a20d2466 249 # Write CA configuration file.
064af421 250 if test ! -e ca.cnf; then
a20d2466 251 sed "s/@ca@/$ca/g;s/@curr_date@/$curr_date/g" > ca.cnf <<'EOF'
064af421
BP
252[ req ]
253prompt = no
254distinguished_name = req_distinguished_name
255
256[ req_distinguished_name ]
257C = US
258ST = CA
259L = Palo Alto
260O = Open vSwitch
261OU = @ca@
a20d2466 262CN = OVS @ca@ CA Certificate (@curr_date@)
064af421
BP
263
264[ ca ]
265default_ca = the_ca
266
267[ the_ca ]
268dir = . # top dir
269database = $dir/index.txt # index file.
270new_certs_dir = $dir/newcerts # new certs dir
271certificate = $dir/cacert.pem # The CA cert
272serial = $dir/serial # serial no file
273private_key = $dir/private/cakey.pem# CA private key
274RANDFILE = $dir/private/.rand # random number file
275default_days = 365 # how long to certify for
276default_crl_days= 30 # how long before next CRL
277default_md = md5 # md to use
278policy = policy # default policy
279email_in_dn = no # Don't add the email into cert DN
280name_opt = ca_default # Subject name display option
281cert_opt = ca_default # Certificate display option
282copy_extensions = none # Don't copy extensions from request
c6c9e1e3 283unique_subject = no # Allow certs with duplicate subjects
064af421
BP
284
285# For the CA policy
286[ policy ]
287countryName = optional
288stateOrProvinceName = optional
289organizationName = match
290organizationalUnitName = optional
291commonName = supplied
292emailAddress = optional
293EOF
294 fi
295
296 # Create certificate authority.
297 if test $keytype = dsa; then
298 newkey=dsa:dsaparam.pem
299 else
300 newkey=rsa:$bits
301 fi
302 openssl req -config ca.cnf -nodes \
303 -newkey $newkey -keyout private/cakey.pem -out careq.pem \
304 1>&3 2>&3
305 openssl ca -config ca.cnf -create_serial -out cacert.pem \
72aa493e 306 -days 2191 -batch -keyfile private/cakey.pem -selfsign \
064af421
BP
307 -infiles careq.pem 1>&3 2>&3
308 chmod 0700 private/cakey.pem
309
310 cd "$oldpwd"
311 done
312 exit 0
313fi
314
315one_arg() {
316 if test -z "$arg1" || test -n "$arg2"; then
317 echo "$0: $command must have exactly one argument; use --help for help" >&2
318 exit 1
319 fi
320}
321
064af421
BP
322one_or_two_args() {
323 if test -z "$arg1"; then
324 echo "$0: $command must have one or two arguments; use --help for help" >&2
325 exit 1
326 fi
327}
328
329must_not_exist() {
330 if test -e "$1" && test "$force" != "yes"; then
331 echo "$0: $1 already exists and --force not supplied" >&2
332 exit 1
333 fi
334}
335
064af421
BP
336make_tmpdir() {
337 TMP=/tmp/ovs-pki.tmp$$
338 rm -rf $TMP
339 trap "rm -rf $TMP" 0
340 mkdir -m 0700 $TMP
341}
342
343fingerprint() {
bb60fa74
BP
344 file=$1
345 name=${1-$2}
0f5ed573 346 date=$(file_mod_date "$file")
00961f7c 347 if grep -e '-BEGIN CERTIFICATE-' "$file" > /dev/null; then
064af421
BP
348 fingerprint=$(openssl x509 -noout -in "$file" -fingerprint |
349 sed 's/SHA1 Fingerprint=//' | tr -d ':')
350 else
351 fingerprint=$(sha1sum "$file" | awk '{print $1}')
352 fi
353 printf "$name\\t$date\\n"
354 case $file in
355 $fingerprint*)
356 printf "\\t(correct fingerprint in filename)\\n"
357 ;;
358 *)
359 printf "\\tfingerprint $fingerprint\\n"
360 ;;
361 esac
362}
363
364verify_fingerprint() {
365 fingerprint "$@"
366 if test $batch != yes; then
367 echo "Does fingerprint match? (yes/no)"
368 read answer
369 if test "$answer" != yes; then
370 echo "Match failure, aborting" >&2
371 exit 1
372 fi
373 fi
374}
375
376check_type() {
377 if test x = x"$1"; then
378 type=switch
379 elif test "$1" = switch || test "$1" = controller; then
380 type=$1
381 else
382 echo "$0: type argument must be 'switch' or 'controller'" >&2
383 exit 1
384 fi
385}
386
387parse_age() {
388 number=$(echo $1 | sed 's/^\([0-9]\+\)\([[:alpha:]]\+\)/\1/')
389 unit=$(echo $1 | sed 's/^\([0-9]\+\)\([[:alpha:]]\+\)/\2/')
390 case $unit in
391 s)
392 factor=1
393 ;;
394 min)
395 factor=60
396 ;;
397 h)
398 factor=3600
399 ;;
400 day)
401 factor=86400
402 ;;
403 *)
404 echo "$1: age not in the form Ns, Nmin, Nh, Nday (e.g. 1day)" >&2
405 exit 1
406 ;;
407 esac
408 echo $(($number * $factor))
409}
410
411must_exist() {
412 if test ! -e "$1"; then
413 echo "$0: $1 does not exist" >&2
414 exit 1
415 fi
416}
417
418pkidir_must_exist() {
419 if test ! -e "$pkidir"; then
420 echo "$0: $pkidir does not exist (need to run 'init' or use '--dir'?)" >&2
421 exit 1
422 elif test ! -d "$pkidir"; then
423 echo "$0: $pkidir is not a directory" >&2
424 exit 1
425 fi
426}
427
428make_request() {
429 must_not_exist "$arg1-privkey.pem"
430 must_not_exist "$arg1-req.pem"
431 make_tmpdir
432 cat > "$TMP/req.cnf" <<EOF
433[ req ]
434prompt = no
435distinguished_name = req_distinguished_name
436
437[ req_distinguished_name ]
438C = US
439ST = CA
440L = Palo Alto
441O = Open vSwitch
442OU = Open vSwitch certifier
443CN = Open vSwitch certificate for $arg1
444EOF
445 if test $keytype = rsa; then
99e5e05d
BP
446 (umask 077 && openssl genrsa -out "$1-privkey.pem" $bits) 1>&3 2>&3 \
447 || exit $?
064af421
BP
448 else
449 must_exist "$dsaparam"
99e5e05d
BP
450 (umask 077 && openssl gendsa -out "$1-privkey.pem" "$dsaparam") \
451 1>&3 2>&3 || exit $?
064af421 452 fi
99e5e05d
BP
453 openssl req -config "$TMP/req.cnf" -new -text \
454 -key "$1-privkey.pem" -out "$1-req.pem" 1>&3 2>&3
064af421
BP
455}
456
457sign_request() {
458 must_exist "$1"
459 must_not_exist "$2"
460 pkidir_must_exist
461
462 (cd "$pkidir/${type}ca" &&
463 openssl ca -config ca.cnf -batch -in /dev/stdin) \
464 < "$1" > "$2.tmp$$" 2>&3
465 mv "$2.tmp$$" "$2"
466}
467
468glob() {
bb60fa74 469 files=$(echo $1)
064af421
BP
470 if test "$files" != "$1"; then
471 echo "$files"
472 fi
473}
474
475exec 3>>$log || true
476if test "$command" = req; then
477 one_arg
478
479 make_request "$arg1"
480 fingerprint "$arg1-req.pem"
481elif test "$command" = sign; then
482 one_or_two_args
483 check_type "$arg2"
484 verify_fingerprint "$arg1-req.pem"
485
486 sign_request "$arg1-req.pem" "$arg2-cert.pem"
487elif test "$command" = req+sign; then
488 one_or_two_args
489 check_type "$arg2"
490
491 pkidir_must_exist
492 make_request "$arg1"
493 sign_request "$arg1-req.pem" "$arg1-cert.pem"
494 fingerprint "$arg1-req.pem"
495elif test "$command" = verify; then
496 one_or_two_args
497 must_exist "$arg1-cert.pem"
498 check_type "$arg2"
499
500 pkidir_must_exist
501 openssl verify -CAfile "$pkidir/${type}ca/cacert.pem" "$arg1-cert.pem"
502elif test "$command" = fingerprint; then
503 one_arg
504
505 fingerprint "$arg1"
506elif test "$command" = self-sign; then
507 one_arg
508 must_exist "$arg1-req.pem"
509 must_exist "$arg1-privkey.pem"
510 must_not_exist "$arg1-cert.pem"
511
99e5e05d
BP
512 # Create both the private key and certificate with restricted permissions.
513 (umask 077 && \
514 openssl x509 -in "$arg1-req.pem" -out "$arg1-cert.pem.tmp" \
515 -signkey "$arg1-privkey.pem" -req -text) 2>&3 || exit $?
516
517 # Reset the permissions on the certificate to the user's default.
518 cat "$arg1-cert.pem.tmp" > "$arg1-cert.pem"
519 rm -f "$arg1-cert.pem.tmp"
064af421
BP
520else
521 echo "$0: $command command unknown; use --help for help" >&2
522 exit 1
523fi