source: npl/internetserver/openvpn_conf/root/etc/openvpn/easyrsa @ c5c522c

gcc484ntopperl-5.22
Last change on this file since c5c522c was c5c522c, checked in by Edwin Eefting <edwin@datux.nl>, 8 years ago

initial commit, transferred from cleaned syn3 svn tree

  • Property mode set to 100755
File size: 34.4 KB
Line 
1#!/bin/sh
2
3# Easy-RSA 3 -- A Shell-based CA Utility
4#
5# Copyright (C) 2013 by the Open-Source OpenVPN development community.
6# A full list of contributors can be found in the ChangeLog.
7#
8# This code released under version 2 of the GNU GPL; see COPYING and the
9# Licensing/ directory of this project for full licensing details.
10
11# Help/usage output to stdout
12usage() {
13        # command help:
14        print "
15Easy-RSA 3 usage and overview
16
17USAGE: easyrsa [options] COMMAND [command-options]
18
19A list of commands is shown below. To get detailed usage and help for a
20command, run:
21  ./easyrsa help COMMAND
22
23For a listing of options that can be supplied before the command, use:
24  ./easyrsa help options
25
26Here is the list of commands available with a short syntax reminder. Use the
27'help' command above to get full usage details.
28
29  init-pki
30  build-ca [ cmd-opts ]
31  gen-dh
32  gen-req <filename_base> [ cmd-opts ]
33  sign-req <type> <filename_base>
34  build-client-full <filename_base> [ cmd-opts ]
35  build-server-full <filename_base> [ cmd-opts ]
36  revoke <filename_base>
37  gen-crl
38  update-db
39  show-req <filename_base> [ cmd-opts ]
40  show-cert <filename_base> [ cmd-opts ]
41  import-req <request_file_path> <short_basename>
42  export-p7 <filename_base> [ cmd-opts ]
43  export-p12 <filename_base> [ cmd-opts ]
44  set-rsa-pass <filename_base> [ cmd-opts ]
45  set-ec-pass <filename_base> [ cmd-opts ]
46"
47
48        # collect/show dir status:
49        local err_source="Not defined: vars autodetect failed and no value provided"
50        local work_dir="${EASYRSA:-$err_source}"
51        local pki_dir="${EASYRSA_PKI:-$err_source}"
52        print "\
53DIRECTORY STATUS (commands would take effect on these locations)
54  EASYRSA: $work_dir
55      PKI:  $pki_dir
56"
57} # => usage()
58
59# Detailed command help
60# When called with no args, calls usage(), otherwise shows help for a command
61cmd_help() {
62        local text opts
63        case "$1" in
64                init-pki|clean-all) text="
65  init-pki [ cmd-opts ]
66      Removes & re-initializes the PKI dir for a clean PKI" ;;
67                build-ca) text="
68  build-ca [ cmd-opts ]
69      Creates a new CA"
70                        opts="
71        nopass  - do not encrypt the CA key (default is encrypted)
72        subca   - create a sub-CA keypair and request (default is a root CA)" ;;
73                gen-dh) text="
74  gen-dh
75      Generates DH (Diffie-Hellman) parameters" ;;
76                gen-req) text="
77  gen-req <filename_base> [ cmd-opts ]
78      Generate a standalone keypair and request (CSR)
79
80      This request is suitable for sending to a remote CA for signing."
81                        opts="
82        nopass  - do not encrypt the private key (default is encrypted)" ;;
83                sign|sign-req) text="
84  sign-req <type> <filename_base>
85      Sign a certificate request of the defined type. <type> must be a known
86      type such as 'client', 'server', or 'ca' (or a user-added type.)
87
88      This request file must exist in the reqs/ dir and have a .req file
89      extension. See import-req below for importing reqs from other sources." ;;
90                build|build-client-full|build-server-full) text="
91  build-client-full <filename_base> [ cmd-opts ]
92  build-server-full <filename_base> [ cmd-opts ]
93      Generate a keypair and sign locally for a client or server
94
95      This mode uses the <filename_base> as the X509 CN."
96                        opts="
97        nopass  - do not encrypt the private key (default is encrypted)" ;;
98                revoke) text="
99  revoke <filename_base>
100      Revoke a certificate specified by the filename_base" ;;
101                gen-crl) text="
102  gen-crl
103      Generate a CRL" ;;
104                update-db) text="
105  update-db
106      Update the index.txt database
107
108      This command will use the system time to update the status of issued
109      certificates." ;;
110                show-req|show-cert) text="
111  show-req  <filename_base> [ cmd-opts ]
112  show-cert <filename_base> [ cmd-opts ]
113      Shows details of the req or cert referenced by filename_base
114
115      Human-readable output is shown, including any requested cert options when
116      showing a request."
117                        opts="
118          full   - show full req/cert info, including pubkey/sig data" ;;
119                import-req) text="
120  import-req <request_file_path> <short_basename>
121      Import a certificate request from a file
122
123      This will copy the specified file into the reqs/ dir in
124      preparation for signing.
125      The <short_basename> is the filename base to create.
126
127      Example usage:
128        import-req /some/where/bob_request.req bob" ;;
129                export-p12) text="
130  export-p12 <filename_base> [ cmd-opts ]
131      Export a PKCS#12 file with the keypair specified by <filename_base>"
132                        opts="
133        noca  - do not include the ca.crt file in the PKCS12 output
134        nokey - do not include the private key in the PKCS12 output" ;;
135                export-p7) text="
136  export-p7 <filename_base> [ cmd-opts ]
137      Export a PKCS#7 file with the pubkey specified by <filename_base>"
138                        opts="
139        noca  - do not include the ca.crt file in the PKCS7 output" ;;
140                set-rsa-pass|set-ec-pass) text="
141  set-rsa-pass <filename_base> [ cmd-opts ]
142  set-ec-pass <filename_base> [ cmd-opts ]
143      Set a new passphrase on an RSA or EC key for the listed <filename_base>."
144                        opts="
145        nopass - use no password and leave the key unencrypted
146        file   - (advanced) treat the file as a raw path, not a short-name" ;;
147                altname|subjectaltname|san) text="
148  --subject-alt-name=SAN_FORMAT_STRING
149      This global option adds a subjectAltName to the request or issued
150      certificate. It MUST be in a valid format accepted by openssl or
151      req/cert generation will fail. Note that including multiple such names
152      requires them to be comma-separated; further invocations of this
153      option will REPLACE the value.
154
155      Examples of the SAN_FORMAT_STRING shown below:
156        DNS:alternate.example.net
157        DNS:primary.example.net,DNS:alternate.example.net
158        IP:203.0.113.29
159        email:alternate@example.net" ;;
160                options)
161                        opt_usage ;;
162                "")
163                        usage ;;
164                *) text="
165  Unknown command: '$1' (try without commands for a list of commands)" ;;
166        esac
167
168        # display the help text
169        print "$text"
170        [ -n "$opts" ] && print "
171      cmd-opts is an optional set of command options from this list:
172$opts"
173} # => cmd_help()
174
175# Options usage
176opt_usage() {
177        print "
178Easy-RSA Global Option Flags
179
180The following options may be provided before the command. Options specified
181at runtime override env-vars and any 'vars' file in use. Unless noted,
182non-empty values to options are mandatory.
183
184General options:
185
186--batch         : set automatic (no-prompts when possible) mode
187--pki-dir=DIR   : declares the PKI directory
188--vars=FILE     : define a specific 'vars' file to use for Easy-RSA config
189
190Certificate & Request options: (these impact cert/req field values)
191
192--days=#        : sets the signing validity to the specified number of days
193--digest=ALG    : digest to use in the requests & certificates
194--dn-mode=MODE  : DN mode to use (cn_only or org)
195--keysize=#     : size in bits of keypair to generate
196--req-cn=NAME   : default CN to use
197--subca-len=#   : path length of signed sub-CA certs; must be >= 0 if used
198--subject-alt-name : Add a subjectAltName. For more info and syntax, see:
199                     ./easyrsa help altname
200--use-algo=ALG  : crypto alg to use: choose rsa (default) or ec
201--curve=NAME    : for elliptic curve, sets the named curve to use
202
203Organizational DN options: (only used with the 'org' DN mode)
204  (values may be blank for org DN options)
205
206--req-c=CC        : country code (2-letters)
207--req-st=NAME     : State/Province
208--req-city=NAME   : City/Locality
209--req-org=NAME    : Organization
210--req-email=NAME  : Email addresses
211--req-ou=NAME     : Organizational Unit
212
213Deprecated features:
214
215--ns-cert=YESNO       : yes or no to including deprecated NS extensions
216--ns-comment=COMMENT  : NS comment to include (value may be blank)
217"
218} # => opt_usage()
219
220# Wrapper around printf - clobber print since it's not POSIX anyway
221print() { printf "%s\n" "$*"; }
222
223# Exit fatally with a message to stderr
224# present even with EASYRSA_BATCH as these are fatal problems
225die() {
226        print "
227Easy-RSA error:
228
229$1" 1>&2
230        exit ${2:-1}
231} # => die()
232
233# non-fatal warning output
234warn() {
235        [ ! $EASYRSA_BATCH ] && \
236                print "
237$1" 1>&2
238} # => warn()
239
240# informational notices to stdout
241notice() {
242        [ ! $EASYRSA_BATCH ] && \
243                print "
244$1"
245} # => notice()
246
247# yes/no case-insensitive match (operates on stdin pipe)
248# Returns 0 when input contains yes, 1 for no, 2 for no match
249# If both strings are present, returns 1; first matching line returns.
250awk_yesno() {
251        local awkscript='
252BEGIN {IGNORECASE=1; r=2}
253{       if(match($0,"no")) {r=1; exit}
254        if(match($0,"yes")) {r=0; exit}
255} END {exit r}'
256        awk "$awkscript"
257} # => awk_yesno()
258
259# intent confirmation helper func
260# returns without prompting in EASYRSA_BATCH
261confirm() {
262        [ $EASYRSA_BATCH ] && return
263        local prompt="$1" value="$2" msg="$3" input
264        print "
265$msg
266
267Type the word '$value' to continue, or any other input to abort."
268        printf %s "  $prompt"
269        read input
270        [ "$input" = "$value" ] && return
271        notice "Aborting without confirmation."
272        exit 9
273} # => confirm()
274
275# remove temp files
276clean_temp() {
277        for f in "$EASYRSA_TEMP_FILE" "$EASYRSA_TEMP_FILE_2" "$EASYRSA_TEMP_FILE_3"
278        do      [ -f "$f" ] && rm "$f" 2>/dev/null
279        done
280} # => clean_temp()
281
282vars_source_check() {
283        # Check for defined EASYRSA_PKI
284        [ -n "$EASYRSA_PKI" ] || die "\
285EASYRSA_PKI env-var undefined"
286
287        # Verify EASYRSA_OPENSSL command gives expected output
288        if [ -z "$EASYRSA_SSL_OK" ]; then
289                local val="$("$EASYRSA_OPENSSL" version)"
290                case "${val%% *}" in
291                        OpenSSL|LibreSSL) ;;
292                        *) die "\
293Missing or invalid OpenSSL
294Expected to find openssl command at: $EASYRSA_OPENSSL"
295                esac
296        fi
297        EASYRSA_SSL_OK=1
298
299        # Verify EASYRSA_SSL_CONF file exists
300        [ -f "$EASYRSA_SSL_CONF" ] || die "\
301The OpenSSL config file cannot be found.
302Expected location: $EASYRSA_SSL_CONF"
303} # => vars_source_check()
304
305# Verify supplied curve exists and generate curve file if needed
306verify_curve() {
307        if ! "$EASYRSA_OPENSSL" ecparam -name "$EASYRSA_CURVE" > /dev/null; then
308                die "\
309Curve $EASYRSA_CURVE not found. Run openssl ecparam -list_curves to show a
310list of supported curves."
311        fi
312
313        # Check that the ecparams dir exists
314        [ -d "$EASYRSA_EC_DIR" ] || mkdir "$EASYRSA_EC_DIR" || die "\
315Failed creating ecparams dir (permissions?) at:
316$EASYRSA_EC_DIR"
317
318        # Check that the required ecparams file exists
319        local out="$EASYRSA_EC_DIR/${EASYRSA_CURVE}.pem"
320        [ -f "$out" ] && return 0
321        "$EASYRSA_OPENSSL" ecparam -name "$EASYRSA_CURVE" -out "$out" || die "\
322Failed to generate ecparam file (permissions?) when writing to:
323$out"
324
325        # Explicitly return success for caller
326        return 0
327}
328
329# Basic sanity-check of PKI init and complain if missing
330verify_pki_init() {
331        local help_note="Run easyrsa without commands for usage and command help."
332
333        # check that the pki dir exists
334        vars_source_check
335        [ -d "$EASYRSA_PKI" ] || die "\
336EASYRSA_PKI does not exist (perhaps you need to run init-pki)?
337Expected to find the EASYRSA_PKI at: $EASYRSA_PKI
338$help_note"
339
340        # verify expected dirs present:
341        for i in private reqs; do
342                [ -d "$EASYRSA_PKI/$i" ] || die "\
343Missing expected directory: $i (perhaps you need to run init-pki?)
344$help_note"
345        done
346} # => verify_pki_init()
347
348# Verify core CA files present
349verify_ca_init() {
350        local help_note="Run without commands for usage and command help."
351
352        # First check the PKI has been initialized
353        verify_pki_init
354
355        # verify expected files present:
356        for i in serial index.txt ca.crt private/ca.key; do
357                if [ ! -f "$EASYRSA_PKI/$i" ]; then
358                        [ "$1" = "test" ] && return 1
359                        die "\
360Missing expected CA file: $i (perhaps you need to run build-ca?)
361$help_note"
362                fi
363        done
364
365        # When operating in 'test' mode, return success.
366        # test callers don't care about CA-specific dir structure
367        [ "$1" = "test" ] && return 0
368
369        # verify expected CA-specific dirs:
370        for i in issued certs_by_serial; do
371                [ -d "$EASYRSA_PKI/$i" ] || die "\
372Missing expected CA dir: $i (perhaps you need to run build-ca?)
373$help_note"
374        done
375
376        # explicitly return success for callers
377        return 0
378
379} # => verify_ca_init()
380
381# init-pki backend:
382init_pki() {
383        vars_source_check
384
385        # If EASYRSA_PKI exists, confirm before we rm -rf (skiped with EASYRSA_BATCH)
386        if [ -e "$EASYRSA_PKI" ]; then
387                confirm "Confirm removal: " "yes" "
388WARNING!!!
389
390You are about to remove the EASYRSA_PKI at: $EASYRSA_PKI
391and initialize a fresh PKI here."
392                # now remove it:
393                rm -rf "$EASYRSA_PKI" || die "Removal of PKI dir failed. Check/correct errors above"
394        fi
395
396        # new dirs:
397        for i in private reqs; do
398                mkdir -p "$EASYRSA_PKI/$i" || die "Failed to create PKI file structure (permissions?)"
399        done
400
401        notice "\
402init-pki complete; you may now create a CA or requests.
403Your newly created PKI dir is: $EASYRSA_PKI
404"
405        return 0
406} # => init_pki()
407
408# build-ca backend:
409build_ca() {
410        local opts= sub_ca=
411        while [ -n "$1" ]; do
412                case "$1" in
413                        nopass) opts="$opts -nodes" ;;
414                        subca) sub_ca=1 ;;
415                        *) warn "Ignoring unknown command option: '$1'" ;;
416                esac
417                shift
418        done
419
420        verify_pki_init
421        [ "$EASYRSA_ALGO" = "ec" ] && verify_curve
422
423        # setup for the simpler sub-CA situation and overwrite with root-CA if needed:
424        local out_file="$EASYRSA_PKI/reqs/ca.req"
425        local out_key="$EASYRSA_PKI/private/ca.key"
426        if [ ! $sub_ca ]; then
427                out_file="$EASYRSA_PKI/ca.crt"
428                opts="$opts -x509 -days $EASYRSA_CA_EXPIRE"
429        fi
430
431        # Test for existing CA, and complain if already present
432        if verify_ca_init test; then
433                die "\
434Unable to create a CA as you already seem to have one set up.
435If you intended to start a new CA, run init-pki first."
436        fi
437        # If a private key exists here, a sub-ca was created but not signed.
438        # Notify the user and require a signed ca.crt or a init-pki:
439        [ -f "$out_key" ] && \
440                die "\
441A CA private key exists but no ca.crt is found in your PKI dir of:
442$EASYRSA_PKI
443Refusing to create a new CA keypair as this operation would overwrite your
444current CA keypair. If you intended to start a new CA, run init-pki first."
445
446        # create necessary files and dirs:
447        local err_file="Unable to create necessary PKI files (permissions?)"
448        for i in issued certs_by_serial; do
449                mkdir -p "$EASYRSA_PKI/$i" || die "$err_file"
450        done
451        printf "" > "$EASYRSA_PKI/index.txt" || die "$err_file"
452        print "01" > "$EASYRSA_PKI/serial" || die "$err_file"
453
454        # Default CN only when not in global EASYRSA_BATCH mode:
455        [ $EASYRSA_BATCH ] && opts="$opts -batch" || export EASYRSA_REQ_CN="Easy-RSA CA"
456
457        out_key_tmp="$(mktemp -u "$out_key.XXXXXXXXXX")"; EASYRSA_TEMP_FILE_2="$out_key_tmp"
458        out_file_tmp="$(mktemp -u "$out_file.XXXXXXXXXX")"; EASYRSA_TEMP_FILE_3="$out_file_tmp"
459        # create the CA keypair:
460        "$EASYRSA_OPENSSL" req -utf8 -new -newkey $EASYRSA_ALGO:"$EASYRSA_ALGO_PARAMS" \
461                -config "$EASYRSA_SSL_CONF" -keyout "$out_key_tmp" -out "$out_file_tmp" $opts || \
462                die "Failed to build the CA"
463        mv "$out_key_tmp" "$out_key"; EASYRSA_TEMP_FILE_2=
464        mv "$out_file_tmp" "$out_file"; EASYRSA_TEMP_FILE_3=
465
466        # Success messages
467        if [ $sub_ca ]; then
468                notice "\
469NOTE: Your sub-CA request is at $out_file
470and now must be sent to you parent CA for signing. Place your resulting cert
471at $EASYRSA_PKI/ca.crt prior to signing operations.
472"
473        else    notice "\
474CA creation complete and you may now import and sign cert requests.
475Your new CA certificate file for publishing is at:
476$out_file
477"
478        fi
479        return 0
480} # => build_ca()
481
482# gen-dh backend:
483gen_dh() {
484        verify_pki_init
485
486        local out_file="$EASYRSA_PKI/dh.pem"
487        "$EASYRSA_OPENSSL" dhparam -out "$out_file" $EASYRSA_KEY_SIZE || \
488                die "Failed to build DH params"
489        notice "\
490DH parameters of size $EASYRSA_KEY_SIZE created at $out_file
491"
492        return 0
493} # => gen_dh()
494
495# gen-req backend:
496gen_req() {
497        # pull filename base and use as default interactive CommonName:
498        [ -n "$1" ] || die "\
499Error: gen-req must have a file base as the first argument.
500Run easyrsa without commands for usage and commands."
501        local key_out="$EASYRSA_PKI/private/$1.key"
502        local req_out="$EASYRSA_PKI/reqs/$1.req"
503        [ ! $EASYRSA_BATCH ] && EASYRSA_REQ_CN="$1"
504        shift
505
506        # function opts support
507        local opts=
508        while [ -n "$1" ]; do
509                case "$1" in
510                        nopass) opts="$opts -nodes" ;;
511                        # batch flag supports internal callers needing silent operation
512                        batch) local EASYRSA_BATCH=1 ;;
513                        *) warn "Ignoring unknown command option: '$1'" ;;
514                esac
515                shift
516        done
517
518        verify_pki_init
519        [ "$EASYRSA_ALGO" = "ec" ] && verify_curve
520
521        # don't wipe out an existing private key without confirmation
522        [ -f "$key_out" ] && confirm "Confirm key overwrite: " "yes" "\
523
524WARNING!!!
525
526An existing private key was found at $key_out
527Continuing with key generation will replace this key."
528
529        # When EASYRSA_EXTRA_EXTS is defined, append it to openssl's [req] section:
530        if [ -n "$EASYRSA_EXTRA_EXTS" ]; then
531                # Setup & insert the extra ext data keyed by a magic line
532                local extra_exts="
533req_extensions = req_extra
534[ req_extra ]
535$EASYRSA_EXTRA_EXTS"
536                local awkscript='
537{if ( match($0, "^#%EXTRA_EXTS%") )
538        { while ( getline<"/dev/stdin" ) {print} next }
539 {print}
540}'
541                print "$extra_exts" | \
542                        awk "$awkscript" "$EASYRSA_SSL_CONF" \
543                        > "$EASYRSA_TEMP_FILE" \
544                        || die "Copying SSL config to temp file failed"
545                # Use this new SSL config for the rest of this function
546                local EASYRSA_SSL_CONF="$EASYRSA_TEMP_FILE"
547        fi
548
549        key_out_tmp="$(mktemp -u "$key_out.XXXXXXXXXX")"; EASYRSA_TEMP_FILE_2="$key_out_tmp"
550        req_out_tmp="$(mktemp -u "$req_out.XXXXXXXXXX")"; EASYRSA_TEMP_FILE_3="$req_out_tmp"
551        # generate request
552        [ $EASYRSA_BATCH ] && opts="$opts -batch"
553        "$EASYRSA_OPENSSL" req -utf8 -new -newkey $EASYRSA_ALGO:"$EASYRSA_ALGO_PARAMS" \
554                -config "$EASYRSA_SSL_CONF" -keyout "$key_out_tmp" -out "$req_out_tmp" $opts \
555                || die "Failed to generate request"
556        mv "$key_out_tmp" "$key_out"; EASYRSA_TEMP_FILE_2=
557        mv "$req_out_tmp" "$req_out"; EASYRSA_TEMP_FILE_3=
558        notice "\
559Keypair and certificate request completed. Your files are:
560req: $req_out
561key: $key_out
562"
563        return 0
564} # => gen_req()
565
566# common signing backend
567sign_req() {
568        local crt_type="$1" opts=
569        local req_in="$EASYRSA_PKI/reqs/$2.req"
570        local crt_out="$EASYRSA_PKI/issued/$2.crt"
571
572        # Support batch by internal caller:
573        [ "$3" = "batch" ] && local EASYRSA_BATCH=1
574
575        verify_ca_init
576
577        # Check argument sanity:
578        [ -n "$2" ] || die "\
579Incorrect number of arguments provided to sign-req:
580expected 2, got $# (see command help for usage)"
581
582        # Cert type must exist under the EASYRSA_EXT_DIR
583        [ -r "$EASYRSA_EXT_DIR/$crt_type" ] || die "\
584Unknown cert type '$crt_type'"
585
586        # Request file must exist
587        [ -f "$req_in" ] || die "\
588No request found for the input: '$2'
589Expected to find the request at: $req_in"
590
591        # Confirm input is a cert req
592        verify_file req "$req_in" || die "\
593The certificate request file is not in a valid X509 request format.
594Offending file: $req_in"
595
596        # Display the request subject in an easy-to-read format
597        # Confirm the user wishes to sign this request
598        confirm "Confirm request details: " "yes" "
599You are about to sign the following certificate.
600Please check over the details shown below for accuracy. Note that this request
601has not been cryptographically verified. Please be sure it came from a trusted
602source or that you have verified the request checksum with the sender.
603
604Request subject, to be signed as a $crt_type certificate for $EASYRSA_CERT_EXPIRE days:
605
606$(display_dn req "$req_in")
607"       # => confirm end
608
609        # Generate the extensions file for this cert:
610        {
611                # Append first any COMMON file (if present) then the cert-type extensions
612                cat "$EASYRSA_EXT_DIR/COMMON"
613                cat "$EASYRSA_EXT_DIR/$crt_type"
614
615                # Support a dynamic CA path length when present:
616                [ "$crt_type" = "ca" ] && [ -n "$EASYRSA_SUBCA_LEN" ] && \
617                        print "basicConstraints = CA:TRUE, pathlen:$EASYRSA_SUBCA_LEN"
618
619                # Deprecated Netscape extension support, if enabled
620                if print "$EASYRSA_NS_SUPPORT" | awk_yesno; then
621                        [ -n "$EASYRSA_NS_COMMENT" ] && \
622                                print "nsComment = \"$EASYRSA_NS_COMMENT\""
623                        case "$crt_type" in
624                                server) print "nsCertType = server" ;;
625                                client) print "nsCertType = client" ;;
626                                ca)     print "nsCertType = sslCA" ;;
627                        esac
628                fi
629
630                # Add any advanced extensions supplied by env-var:
631                [ -n "$EASYRSA_EXTRA_EXTS" ] && print "$EASYRSA_EXTRA_EXTS"
632               
633                : # needed to keep die from inherting the above test
634        } > "$EASYRSA_TEMP_FILE" || die "\
635Failed to create temp extension file (bad permissions?) at:
636$EASYRSA_TEMP_FILE"
637
638        # sign request
639        crt_out_tmp="$(mktemp -u "$crt_out.XXXXXXXXXX")"; EASYRSA_TEMP_FILE_2="$crt_out_tmp"
640        "$EASYRSA_OPENSSL" ca -utf8 -in "$req_in" -out "$crt_out_tmp" -config "$EASYRSA_SSL_CONF" \
641                -extfile "$EASYRSA_TEMP_FILE" -days $EASYRSA_CERT_EXPIRE -batch $opts \
642                || die "signing failed (openssl output above may have more detail)"
643        mv "$crt_out_tmp" "$crt_out"; EASYRSA_TEMP_FILE_2=
644        notice "\
645Certificate created at: $crt_out
646"
647        return 0
648} # => sign_req()
649
650# common build backend
651# used to generate+sign in 1 step
652build_full() {
653        verify_ca_init
654
655        local i= serial= check_serial=
656        for i in 1 2 3 4 5; do
657                "$EASYRSA_OPENSSL" rand -hex 16 -out "$EASYRSA_PKI/serial"
658                serial="$(cat "$EASYRSA_PKI/serial")"
659                check_serial="$("$EASYRSA_OPENSSL" ca -config "$EASYRSA_SSL_CONF" -status "$serial" 2>&1)"
660                case "$check_serial" in
661                        *"not present in db"*) break ;;
662                        *) continue ;;
663                esac
664        done
665
666        # pull filename base:
667        [ -n "$2" ] || die "\
668Error: didn't find a file base name as the first argument.
669Run easyrsa without commands for usage and commands."
670        local crt_type="$1" name="$2"
671        local req_out="$EASYRSA_PKI/reqs/$2.req"
672        local key_out="$EASYRSA_PKI/private/$2.key"
673        local crt_out="$EASYRSA_PKI/issued/$2.crt"
674        shift 2
675
676        # function opts support
677        local req_opts=
678        while [ -n "$1" ]; do
679                case "$1" in
680                        nopass) req_opts="$req_opts nopass" ;;
681                        *) warn "Ignoring unknown command option: '$1'" ;;
682                esac
683                shift
684        done
685
686        # abort on existing req/key/crt files
687        local err_exists="\
688file already exists. Aborting build to avoid overwriting this file.
689If you wish to continue, please use a different name or remove the file.
690Matching file found at: "
691        [ -f "$req_out" ] && die "Request $err_exists $req_out"
692        [ -f "$key_out" ] && die "Key $err_exists $key_out"
693        [ -f "$crt_out" ] && die "Certificate $err_exists $crt_out"
694
695        # create request
696        EASYRSA_REQ_CN="$name"
697        gen_req "$name" batch $req_opts
698
699        # Sign it
700        sign_req "$crt_type" "$name" batch
701
702} # => build_full()
703
704# revoke backend
705revoke() {
706        verify_ca_init
707
708        # pull filename base:
709        [ -n "$1" ] || die "\
710Error: didn't find a file base name as the first argument.
711Run easyrsa without commands for usage and command help."
712        local crt_in="$EASYRSA_PKI/issued/$1.crt"
713
714        verify_file x509 "$crt_in" || die "\
715Unable to revoke as the input file is not a valid certificate. Unexpected
716input in file: $crt_in"
717
718        # confirm operation by displaying DN:
719        confirm "Continue with revocation: " "yes" "
720Please confirm you wish to revoke the certificate with the following subject:
721
722$(display_dn x509 "$crt_in")
723"       # => confirm end
724
725        # referenced cert must exist:
726        [ -f "$crt_in" ] || die "\
727Unable to revoke as no certificate was found. Certificate was expected
728at: $crt_in"
729
730        "$EASYRSA_OPENSSL" ca -utf8 -revoke "$crt_in" -config "$EASYRSA_SSL_CONF" || die "\
731Failed to revoke certificate: revocation command failed."
732
733        notice "\
734IMPORTANT!!!
735
736Revocation was successful. You must run gen-crl and upload a CRL to your
737infrastructure in order to prevent the revoked cert from being accepted.
738"       # => notice end
739        return 0
740} #= revoke()
741
742# gen-crl backend
743gen_crl() {
744        verify_ca_init
745
746        local out_file="$EASYRSA_PKI/crl.pem"
747        out_file_tmp="$(mktemp -u "$out_file.XXXXXXXXXX")"; EASYRSA_TEMP_FILE_2="$out_file_tmp"
748        "$EASYRSA_OPENSSL" ca -utf8 -gencrl -out "$out_file_tmp" -config "$EASYRSA_SSL_CONF" || die "\
749CRL Generation failed.
750"
751        mv "$out_file_tmp" "$out_file"; EASYRSA_TEMP_FILE_2=
752
753        notice "\
754An updated CRL has been created.
755CRL file: $out_file
756"
757        return 0
758} # => gen_crl()
759
760# import-req backend
761import_req() {
762        verify_pki_init
763
764        # pull passed paths
765        local in_req="$1" short_name="$2"
766        local out_req="$EASYRSA_PKI/reqs/$2.req"
767
768        [ -n "$short_name" ] || die "\
769Unable to import: incorrect command syntax.
770Run easyrsa without commands for usage and command help."
771
772        verify_file req "$in_req" || die "\
773The input file does not appear to be a certificate request. Aborting import.
774Offending file: $in_req"
775
776        # destination must not exist
777        [ -f "$out_req" ] && die "\
778Unable to import the request as the destination file already exists.
779Please choose a different name for your imported request file.
780Existing file at: $out_req"
781       
782        # now import it
783        cp "$in_req" "$out_req"
784
785        notice "\
786The request has been successfully imported with a short name of: $short_name
787You may now use this name to perform signing operations on this request.
788"
789        return 0
790} # => import_req()
791
792# export pkcs#12 or pkcs#7
793export_pkcs() {
794        local pkcs_type="$1"
795        shift
796
797        [ -n "$1" ] || die "\
798Unable to export p12: incorrect command syntax.
799Run easyrsa without commands for usage and command help."
800
801        local short_name="$1"
802        local crt_in="$EASYRSA_PKI/issued/$1.crt"
803        local key_in="$EASYRSA_PKI/private/$1.key"
804        local crt_ca="$EASYRSA_PKI/ca.crt"
805        shift
806
807        verify_pki_init
808
809        # opts support
810        local want_ca=1
811        local want_key=1
812        while [ -n "$1" ]; do
813                case "$1" in
814                        noca) want_ca= ;;
815                        nokey) want_key= ;;
816                        *) warn "Ignoring unknown command option: '$1'" ;;
817                esac
818                shift
819        done
820
821        local pkcs_opts=
822        if [ $want_ca ]; then
823                verify_file x509 "$crt_ca" || die "\
824Unable to include CA cert in the $pkcs_type output (missing file, or use noca option.)
825Missing file expected at: $crt_ca"
826                pkcs_opts="$pkcs_opts -certfile $crt_ca"
827        fi
828
829        # input files must exist
830        verify_file x509 "$crt_in" || die "\
831Unable to export $pkcs_type for short name '$short_name' without the certificate.
832Missing cert expected at: $crt_in"
833
834        case "$pkcs_type" in
835        p12)
836                local pkcs_out="$EASYRSA_PKI/private/$short_name.p12"
837
838                if [ $want_key ]; then
839                        [ -f "$key_in" ] || die "\
840Unable to export p12 for short name '$short_name' without the key
841(if you want a p12 without the private key, use nokey option.)
842Missing key expected at: $key_in"
843                else
844                        pkcs_opts="$pkcs_opts -nokeys"
845                fi
846
847                # export the p12:
848                "$EASYRSA_OPENSSL" pkcs12 -in "$crt_in" -inkey "$key_in" -export \
849                        -out "$pkcs_out" $pkcs_opts || die "\
850Export of p12 failed: see above for related openssl errors."
851        ;;
852        p7)
853                local pkcs_out="$EASYRSA_PKI/issued/$short_name.p7b"
854
855                # export the p7:
856                "$EASYRSA_OPENSSL" crl2pkcs7 -nocrl -certfile "$crt_in" \
857                        -out "$pkcs_out" $pkcs_opts || die "\
858Export of p7 failed: see above for related openssl errors."
859        ;;
860esac
861
862        notice "\
863Successful export of $pkcs_type file. Your exported file is at the following
864location: $pkcs_out
865"
866        return 0
867} # => export_pkcs()
868
869# set-pass backend
870set_pass() {
871        verify_pki_init
872
873        # key type, supplied internally from frontend command call (rsa/ec)
874        local key_type="$1"
875
876        # values supplied by the user:
877        local raw_file="$2"
878        local file="$EASYRSA_PKI/private/$raw_file.key"
879        [ -n "$raw_file" ] || die "\
880Missing argument to 'set-$key_type-pass' command: no name/file supplied.
881See help output for usage details."
882
883        # parse command options
884        shift 2
885        local crypto="-aes256"
886        while [ -n "$1" ]; do
887                case "$1" in
888                        nopass) crypto= ;;
889                        file)   file="$raw_file" ;;
890                        *)      warn "Ignoring unknown command option: '$1'" ;;
891                esac
892                shift
893        done
894
895        [ -f "$file" ] || die "\
896Missing private key: expected to find the private key component at:
897$file"
898
899        notice "\
900If the key is currently encrypted you must supply the decryption passphrase.
901${crypto:+You will then enter a new PEM passphrase for this key.$NL}"
902
903        "$EASYRSA_OPENSSL" $key_type -in "$file" -out "$file" $crypto || die "\
904Failed to change the private key passphrase. See above for possible openssl
905error messages."
906
907        notice "Key passphrase successfully changed"
908       
909} # => set_pass()
910
911# update-db backend
912update_db() {
913        verify_ca_init
914
915        "$EASYRSA_OPENSSL" ca -utf8 -updatedb -config "$EASYRSA_SSL_CONF" || die "\
916Failed to perform update-db: see above for related openssl errors."
917        return 0
918} # => update_db()
919
920# display cert DN info on a req/X509, passed by full pathname
921display_dn() {
922        local format="$1" path="$2"
923        print "$("$EASYRSA_OPENSSL" $format -in "$path" -noout -subject -nameopt multiline)"
924} # => display_dn()
925
926# verify a file seems to be a valid req/X509
927verify_file() {
928        local format="$1" path="$2"
929        "$EASYRSA_OPENSSL" $format -in "$path" -noout 2>/dev/null || return 1
930        return 0
931} # => verify_file()
932
933# show-* command backend
934# Prints req/cert details in a readable format
935show() {
936        local type="$1" name="$2" in_file format
937        [ -n "$name" ] || die "\
938Missing expected filename_base argument.
939Run easyrsa without commands for usage help."
940        shift 2
941
942        # opts support
943        local opts="-${type}opt no_pubkey,no_sigdump"
944        while [ -n "$1" ]; do
945                case "$1" in
946                        full) opts= ;;
947                        *) warn "Ignoring unknown command option: '$1'" ;;
948                esac
949                shift
950        done
951
952        # Determine cert/req type
953        if [ "$type" = "cert" ]; then
954                verify_ca_init
955                in_file="$EASYRSA_PKI/issued/${name}.crt"
956                format="x509"
957        else
958                verify_pki_init
959                in_file="$EASYRSA_PKI/reqs/${name}.req"
960                format="req"
961        fi
962
963        # Verify file exists and is of the correct type
964        [ -f "$in_file" ] || die "\
965No such $type file with a basename of '$name' is present.
966Expected to find this file at:
967$in_file"
968        verify_file $format "$in_file" || die "\
969This file is not a valid $type file:
970$in_file"
971
972        notice "\
973Showing $type details for '$name'.
974This file is stored at:
975$in_file
976"
977        "$EASYRSA_OPENSSL" $format -in "$in_file" -noout -text\
978                -nameopt multiline $opts || die "\
979OpenSSL failure to process the input"
980} # => show()
981
982# vars setup
983# Here sourcing of 'vars' if present occurs. If not present, defaults are used
984# to support running without a sourced config format
985vars_setup() {
986        # Try to locate a 'vars' file in order of location preference.
987        # If one is found, source it
988        local vars=
989
990        # set up program path
991        local prog_vars="${0%/*}/vars"
992
993        # command-line path:
994        if [ -f "$EASYRSA_VARS_FILE" ]; then
995                vars="$EASYRSA_VARS_FILE"
996        # EASYRSA_PKI, if defined:
997        elif [ -n "$EASYRSA_PKI" ] && [ -f "$EASYRSA_PKI/vars" ]; then
998                vars="$EASYRSA_PKI/vars"
999        # EASYRSA, if defined:
1000        elif [ -n "$EASYRSA" ] && [ -f "$EASYRSA/vars" ]; then
1001                vars="$EASYRSA/vars"
1002        # program location:
1003        elif [ -f "$prog_vars" ]; then
1004                vars="$prog_vars"
1005        fi
1006       
1007        # If a vars file was located, source it
1008        # If $EASYRSA_NO_VARS is defined (not blank) this is skipped
1009        if [ -z "$EASYRSA_NO_VARS" ] && [ -n "$vars" ]; then
1010                EASYRSA_CALLER=1 . "$vars"
1011                notice "\
1012Note: using Easy-RSA configuration from: $vars"
1013        fi
1014       
1015        # Set defaults, preferring existing env-vars if present
1016        set_var EASYRSA         "$PWD"
1017        set_var EASYRSA_OPENSSL openssl
1018        set_var EASYRSA_PKI     "$EASYRSA/pki"
1019        set_var EASYRSA_DN      cn_only
1020        set_var EASYRSA_REQ_COUNTRY     "US"
1021        set_var EASYRSA_REQ_PROVINCE    "California"
1022        set_var EASYRSA_REQ_CITY        "San Francisco"
1023        set_var EASYRSA_REQ_ORG         "Copyleft Certificate Co"
1024        set_var EASYRSA_REQ_EMAIL       me@example.net
1025        set_var EASYRSA_REQ_OU          "My Organizational Unit"
1026        set_var EASYRSA_ALGO            rsa
1027        set_var EASYRSA_KEY_SIZE        2048
1028        set_var EASYRSA_CURVE           secp384r1
1029        set_var EASYRSA_EC_DIR          "$EASYRSA_PKI/ecparams"
1030        set_var EASYRSA_CA_EXPIRE       3650
1031        set_var EASYRSA_CERT_EXPIRE     3650
1032        set_var EASYRSA_CRL_DAYS        180
1033        set_var EASYRSA_NS_SUPPORT      no
1034        set_var EASYRSA_NS_COMMENT      "Easy-RSA Generated Certificate"
1035        set_var EASYRSA_TEMP_FILE       "$EASYRSA_PKI/extensions.temp"
1036        set_var EASYRSA_TEMP_FILE_2     ""
1037        set_var EASYRSA_TEMP_FILE_3     ""
1038        set_var EASYRSA_REQ_CN          ChangeMe
1039        set_var EASYRSA_DIGEST          sha256
1040
1041        # Detect openssl config, preferring EASYRSA_PKI over EASYRSA
1042        if [ -f "$EASYRSA_PKI/openssl-1.0.cnf" ]; then
1043                set_var EASYRSA_SSL_CONF        "$EASYRSA_PKI/openssl-1.0.cnf"
1044        else    set_var EASYRSA_SSL_CONF        "$EASYRSA/openssl-1.0.cnf"
1045        fi
1046
1047        # Same as above for the x509-types extensions dir
1048        if [ -d "$EASYRSA_PKI/x509-types" ]; then
1049                set_var EASYRSA_EXT_DIR         "$EASYRSA_PKI/x509-types"
1050        else    set_var EASYRSA_EXT_DIR         "$EASYRSA/x509-types"
1051        fi
1052
1053        # EASYRSA_ALGO_PARAMS must be set depending on selected algo
1054        if [ "ec" = "$EASYRSA_ALGO" ]; then
1055                EASYRSA_ALGO_PARAMS="$EASYRSA_EC_DIR/${EASYRSA_CURVE}.pem"
1056        elif [ "rsa" = "$EASYRSA_ALGO" ]; then
1057                EASYRSA_ALGO_PARAMS="${EASYRSA_KEY_SIZE}"
1058        else
1059                die "Alg '$EASYRSA_ALGO' is invalid: must be 'rsa' or 'ec'"
1060        fi
1061
1062        # Setting OPENSSL_CONF prevents bogus warnings (especially useful on win32)
1063        export OPENSSL_CONF="$EASYRSA_SSL_CONF"
1064} # vars_setup()
1065
1066# variable assignment by indirection when undefined; merely exports
1067# the variable when it is already defined (even if currently null)
1068# Sets $1 as the value contained in $2 and exports (may be blank)
1069set_var() {
1070        local var=$1
1071        shift
1072        local value="$*"
1073        eval "export $var=\"\${$var-$value}\""
1074} #=> set_var()
1075
1076########################################
1077# Invocation entry point:
1078
1079NL='
1080'
1081
1082# Be secure with a restrictive umask
1083[ -z "$EASYRSA_NO_UMASK" ] && umask 077
1084
1085# Parse options
1086while :; do
1087        # Separate option from value:
1088        opt="${1%%=*}"
1089        val="${1#*=}"
1090        empty_ok= # Empty values are not allowed unless excepted
1091
1092        case "$opt" in
1093        --days)
1094                export EASYRSA_CERT_EXPIRE="$val"
1095                export EASYRSA_CA_EXPIRE="$val"
1096                export EASYRSA_CRL_DAYS="$val"
1097                ;;
1098        --pki-dir)
1099                export EASYRSA_PKI="$val" ;;
1100        --use-algo)
1101                export EASYRSA_ALGO="$val" ;;
1102        --keysize)
1103                export EASYRSA_KEY_SIZE="$val" ;;
1104        --curve)
1105                export EASYRSA_CURVE="$val" ;;
1106        --dn-mode)
1107                export EASYRSA_DN="$val" ;;
1108        --req-cn)
1109                export EASYRSA_REQ_CN="$val" ;;
1110        --digest)
1111                export EASYRSA_DIGEST="$val" ;;
1112        --req-c)
1113                empty_ok=1
1114                export EASYRSA_REQ_COUNTRY="$val" ;;
1115        --req-st)
1116                empty_ok=1
1117                export EASYRSA_REQ_PROVINCE="$val" ;;
1118        --req-city)
1119                empty_ok=1
1120                export EASYRSA_REQ_CITY="$val" ;;
1121        --req-org)
1122                empty_ok=1
1123                export EASYRSA_REQ_ORG="$val" ;;
1124        --req-email)
1125                empty_ok=1
1126                export EASYRSA_REQ_EMAIL="$val" ;;
1127        --req-ou)
1128                empty_ok=1
1129                export EASYRSA_REQ_OU="$val" ;;
1130        --ns-cert)
1131                export EASYRSA_NS_SUPPORT="$val" ;;
1132        --ns-comment)
1133                empty_ok=1
1134                export EASYRSA_NS_COMMENT="$val" ;;
1135        --batch)
1136                empty_ok=1
1137                export EASYRSA_BATCH=1 ;;
1138        --subca-len)
1139                export EASYRSA_SUBCA_LEN="$val" ;;
1140        --vars)
1141                export EASYRSA_VARS_FILE="$val" ;;
1142        --subject-alt-name)
1143                export EASYRSA_EXTRA_EXTS="\
1144$EASYRSA_EXTRA_EXTS
1145subjectAltName = $val" ;;
1146        *)
1147                break ;;
1148        esac
1149
1150        # fatal error when no value was provided
1151        if [ ! $empty_ok ] && { [ "$val" = "$1" ] || [ -z "$val" ]; }; then
1152                die "Missing value to option: $opt"
1153        fi
1154
1155        shift
1156done
1157
1158# Intelligent env-var detection and auto-loading:
1159vars_setup
1160
1161# Register clean_temp on EXIT
1162trap "clean_temp" EXIT
1163
1164# determine how we were called, then hand off to the function responsible
1165cmd="$1"
1166[ -n "$1" ] && shift # scrape off command
1167case "$cmd" in
1168        init-pki|clean-all)
1169                init_pki "$@"
1170                ;;
1171        build-ca)
1172                build_ca "$@"
1173                ;;
1174        gen-dh)
1175                gen_dh
1176                ;;
1177        gen-req)
1178                gen_req "$@"
1179                ;;
1180        sign|sign-req)
1181                sign_req "$@"
1182                ;;
1183        build-client-full)
1184                build_full client "$@"
1185                ;;
1186        build-server-full)
1187                build_full server "$@"
1188                ;;
1189        gen-crl)
1190                gen_crl
1191                ;;
1192        revoke)
1193                revoke "$@"
1194                ;;
1195        import-req)
1196                import_req "$@"
1197                ;;
1198        export-p12)
1199                export_pkcs p12 "$@"
1200                ;;
1201        export-p7)
1202                export_pkcs p7 "$@"
1203                ;;
1204        set-rsa-pass)
1205                set_pass rsa "$@"
1206                ;;
1207        set-ec-pass)
1208                set_pass ec "$@"
1209                ;;
1210        update-db)
1211                update_db
1212                ;;
1213        show-req)
1214                show req "$@"
1215                ;;
1216        show-cert)
1217                show cert "$@"
1218                ;;
1219        ""|help|-h|--help|--usage)
1220                cmd_help "$1"
1221                exit 0
1222                ;;
1223        *)
1224                die "Unknown command '$cmd'. Run without commands for usage help."
1225                ;;
1226esac
1227
1228# vim: ft=sh nu ai sw=8 ts=8
Note: See TracBrowser for help on using the repository browser.