最后活跃于 2 years ago

ca.sh 原始文件
1#!/bin/bash
2
3# Source: https://jamielinux.com/docs/openssl-certificate-authority/index.html
4
5if [ -z "$1" ]; then
6 echo "=x=> Path for your CA root is required!"
7 exit 1
8fi
9
10CA_ROOT=$(realpath "$1")
11
12# Intermediate directory
13INTERMEDIATE_ROOT="$CA_ROOT/intermediate"
14
15# Static config blanks
16
17read -r -d '' OPENSSL_CA_CFG << EOM
18# OpenSSL root CA configuration file.
19# Auto-generated.
20
21[ ca ]
22# \`man ca\`
23default_ca = CA_default
24
25[ CA_default ]
26# Directory and file locations.
27dir = $CA_ROOT
28certs = \$dir/certs
29crl_dir = \$dir/crl
30new_certs_dir = \$dir/newcerts
31database = \$dir/index.txt
32serial = \$dir/serial
33RANDFILE = \$dir/private/.rand
34
35# The root key and root certificate.
36private_key = \$dir/private/ca.key.pem
37certificate = \$dir/certs/ca.cert.pem
38
39# For certificate revocation lists.
40crlnumber = \$dir/crlnumber
41crl = \$dir/crl/ca.crl.pem
42crl_extensions = crl_ext
43default_crl_days = 30
44
45# SHA-1 is deprecated, so use SHA-2 instead.
46default_md = sha256
47
48name_opt = ca_default
49cert_opt = ca_default
50default_days = 375
51preserve = no
52policy = policy_strict
53
54[ policy_strict ]
55# The root CA should only sign intermediate certificates that match.
56# See the POLICY FORMAT section of \`man ca\`.
57countryName = match
58stateOrProvinceName = match
59organizationName = match
60organizationalUnitName = optional
61commonName = supplied
62emailAddress = optional
63
64[ policy_loose ]
65# Allow the intermediate CA to sign a more diverse range of certificates.
66# See the POLICY FORMAT section of the \`ca\` man page.
67countryName = optional
68stateOrProvinceName = optional
69localityName = optional
70organizationName = optional
71organizationalUnitName = optional
72commonName = supplied
73emailAddress = optional
74
75[ req ]
76# Options for the \`req\` tool (\`man req\`).
77default_bits = 4096
78distinguished_name = req_distinguished_name
79string_mask = utf8only
80
81# SHA-1 is deprecated, so use SHA-2 instead.
82default_md = sha256
83
84# Extension to add when the -x509 option is used.
85x509_extensions = v3_ca
86
87[ req_distinguished_name ]
88# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
89countryName = Country Name (2 letter code)
90stateOrProvinceName = State or Province Name
91localityName = Locality Name
920.organizationName = Organization Name
93organizationalUnitName = Organizational Unit Name
94commonName = Common Name
95emailAddress = Email Address
96
97[ v3_ca ]
98# Extensions for a typical CA (\`man x509v3_config\`).
99subjectKeyIdentifier = hash
100authorityKeyIdentifier = keyid:always,issuer
101basicConstraints = critical, CA:true
102keyUsage = critical, digitalSignature, cRLSign, keyCertSign
103
104[ v3_intermediate_ca ]
105# Extensions for a typical intermediate CA (\`man x509v3_config\`).
106subjectKeyIdentifier = hash
107authorityKeyIdentifier = keyid:always,issuer
108basicConstraints = critical, CA:true, pathlen:0
109keyUsage = critical, digitalSignature, cRLSign, keyCertSign
110
111[ usr_cert ]
112# Extensions for client certificates (\`man x509v3_config\`).
113basicConstraints = CA:FALSE
114nsCertType = client, email
115nsComment = "OpenSSL Generated Client Certificate"
116subjectKeyIdentifier = hash
117authorityKeyIdentifier = keyid,issuer
118keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
119extendedKeyUsage = clientAuth, emailProtection
120
121[ server_cert ]
122# Extensions for server certificates (\`man x509v3_config\`).
123basicConstraints = CA:FALSE
124nsCertType = server
125nsComment = "OpenSSL Generated Server Certificate"
126subjectKeyIdentifier = hash
127authorityKeyIdentifier = keyid,issuer:always
128keyUsage = critical, digitalSignature, keyEncipherment
129extendedKeyUsage = serverAuth
130
131[ crl_ext ]
132# Extension for CRLs (\`man x509v3_config\`).
133authorityKeyIdentifier=keyid:always
134
135[ ocsp ]
136# Extension for OCSP signing certificates (\`man ocsp\`).
137basicConstraints = CA:FALSE
138subjectKeyIdentifier = hash
139authorityKeyIdentifier = keyid,issuer
140keyUsage = critical, digitalSignature
141extendedKeyUsage = critical, OCSPSigning
142
143EOM
144
145read -r -d '' OPENSSL_INTERMEDIATE_CFG << EOM
146# OpenSSL intermediate CA configuration file.
147# Auto-generated.
148
149[ ca ]
150# \`man ca\`
151default_ca = CA_default
152
153[ CA_default ]
154# Directory and file locations.
155dir = $INTERMEDIATE_ROOT
156certs = \$dir/certs
157crl_dir = \$dir/crl
158new_certs_dir = \$dir/newcerts
159database = \$dir/index.txt
160serial = \$dir/serial
161RANDFILE = \$dir/private/.rand
162
163# The root key and root certificate.
164private_key = \$dir/private/intermediate.key.pem
165certificate = \$dir/certs/intermediate.cert.pem
166
167# For certificate revocation lists.
168crlnumber = \$dir/crlnumber
169crl = \$dir/crl/intermediate.crl.pem
170crl_extensions = crl_ext
171default_crl_days = 30
172
173# SHA-1 is deprecated, so use SHA-2 instead.
174default_md = sha256
175
176name_opt = ca_default
177cert_opt = ca_default
178default_days = 375
179preserve = no
180policy = policy_loose
181
182# Allow copying extensions from CSRs
183copy_extensions = copy
184
185[ policy_strict ]
186# The root CA should only sign intermediate certificates that match.
187# See the POLICY FORMAT section of \`man ca\`.
188countryName = match
189stateOrProvinceName = match
190organizationName = match
191organizationalUnitName = optional
192commonName = supplied
193emailAddress = optional
194
195[ policy_loose ]
196# Allow the intermediate CA to sign a more diverse range of certificates.
197# See the POLICY FORMAT section of the \`ca\` man page.
198countryName = optional
199stateOrProvinceName = optional
200localityName = optional
201organizationName = optional
202organizationalUnitName = optional
203commonName = supplied
204emailAddress = optional
205
206[ req ]
207# Options for the \`req\` tool (\`man req\`).
208default_bits = 4096
209distinguished_name = req_distinguished_name
210string_mask = utf8only
211
212# SHA-1 is deprecated, so use SHA-2 instead.
213default_md = sha256
214
215# Extension to add when the -x509 option is used.
216x509_extensions = v3_intermediate_ca
217
218[ req_distinguished_name ]
219# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
220countryName = Country Name (2 letter code)
221stateOrProvinceName = State or Province Name
222localityName = Locality Name
2230.organizationName = Organization Name
224organizationalUnitName = Organizational Unit Name
225commonName = Common Name
226emailAddress = Email Address
227
228[ v3_ca ]
229# Extensions for a typical CA (\`man x509v3_config\`).
230subjectKeyIdentifier = hash
231authorityKeyIdentifier = keyid:always,issuer
232basicConstraints = critical, CA:true
233keyUsage = critical, digitalSignature, cRLSign, keyCertSign
234
235[ v3_intermediate_ca ]
236# Extensions for a typical intermediate CA (\`man x509v3_config\`).
237subjectKeyIdentifier = hash
238authorityKeyIdentifier = keyid:always,issuer
239basicConstraints = critical, CA:true, pathlen:0
240keyUsage = critical, digitalSignature, cRLSign, keyCertSign
241
242[ usr_cert ]
243# Extensions for client certificates (\`man x509v3_config\`).
244basicConstraints = CA:FALSE
245nsCertType = client, email
246nsComment = "OpenSSL Generated Client Certificate"
247subjectKeyIdentifier = hash
248authorityKeyIdentifier = keyid,issuer
249keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
250extendedKeyUsage = clientAuth, emailProtection
251
252[ server_cert ]
253# Extensions for server certificates (\`man x509v3_config\`).
254basicConstraints = CA:FALSE
255nsCertType = server
256nsComment = "OpenSSL Generated Server Certificate"
257subjectKeyIdentifier = hash
258authorityKeyIdentifier = keyid,issuer:always
259keyUsage = critical, digitalSignature, keyEncipherment
260extendedKeyUsage = serverAuth
261
262[ crl_ext ]
263# Extension for CRLs (\`man x509v3_config\`).
264authorityKeyIdentifier=keyid:always
265
266[ ocsp ]
267# Extension for OCSP signing certificates (\`man ocsp\`).
268basicConstraints = CA:FALSE
269subjectKeyIdentifier = hash
270authorityKeyIdentifier = keyid,issuer
271keyUsage = critical, digitalSignature
272extendedKeyUsage = critical, OCSPSigning
273
274EOM
275
276deployFiles () {
277 echo "Deploying a Certificate Authority to $CA_ROOT"
278 echo ''
279
280 if [ ! -d "$CA_ROOT" ]; then
281 # Create directory
282 mkdir -p "$CA_ROOT"
283
284 # Create sub-directories
285 mkdir -p "$CA_ROOT/private" "$CA_ROOT/csr" "$CA_ROOT/certs" "$CA_ROOT/newcerts"
286 touch "$CA_ROOT/index.txt"
287 echo 1000 > "$CA_ROOT/serial"
288
289 chmod 700 "$CA_ROOT/private"
290 echo "$OPENSSL_CA_CFG" > "$CA_ROOT/openssl.cfg"
291 fi
292
293 if [ ! -d "$INTERMEDIATE_ROOT" ]; then
294 mkdir -p "$INTERMEDIATE_ROOT/private" "$INTERMEDIATE_ROOT/csr" "$INTERMEDIATE_ROOT/certs" "$INTERMEDIATE_ROOT/newcerts"
295 touch "$INTERMEDIATE_ROOT/index.txt"
296 echo 1000 > "$INTERMEDIATE_ROOT/serial"
297
298 chmod 700 "$INTERMEDIATE_ROOT/private"
299 echo "$OPENSSL_INTERMEDIATE_CFG" > "$INTERMEDIATE_ROOT/openssl.cfg"
300 fi
301}
302
303generateRootPair () {
304 ############################
305 # GENERATING ROOT KEY PAIR #
306 ############################
307
308 echo '==> Starting the generation of the root key pair.'
309 echo '==> Please fill in the appropriate information asked.'
310 echo ''
311
312 # Set CWD
313 cd "$CA_ROOT"
314
315 # CA Root Private Key
316 if [ ! -e "$CA_ROOT/private/ca.key.pem" ]; then
317 echo '=> Generating CA key.. Please enter a strong passphrase.'
318 echo ''
319 openssl genrsa -aes256 -out private/ca.key.pem 4096
320 else
321 echo '=> Root CA key exists, skipping..'
322 fi
323
324 if [ ! -e "$CA_ROOT/private/ca.key.pem" ]; then
325 echo '=x=> Root CA key was not generated!'
326 return 1
327 fi
328 chmod 400 private/ca.key.pem
329
330 # CA Root Certificate
331 if [ ! -e "$CA_ROOT/certs/ca.cert.pem" ]; then
332 echo '=> Generating CA certificate..'
333 echo ''
334 openssl req -config "$CA_ROOT/openssl.cfg" \
335 -key private/ca.key.pem \
336 -new -x509 -days 7300 -sha256 -extensions v3_ca \
337 -out certs/ca.cert.pem
338 else
339 echo '=> Root certificate exists, skipping..'
340 fi
341
342 if [ ! -e "$CA_ROOT/certs/ca.cert.pem" ]; then
343 echo '=x=> Root certificate was not generated!'
344 return 1
345 fi
346 chmod 444 certs/ca.cert.pem
347
348 # Print info
349 openssl x509 -noout -text -in certs/ca.cert.pem
350
351 echo '==> Root key pair generated.'
352 echo ''
353}
354
355generateIntermediate () {
356 if [ ! -e "$CA_ROOT/certs/ca.cert.pem" ]; then
357 echo '=x=> Could not generate intermediate certificate.'
358 echo '=x=> CA certificate is missing!'
359 return 1
360 fi
361
362 ####################################
363 # GENERATING INTERMEDIATE KEY PAIR #
364 ####################################
365
366 cd "$CA_ROOT"
367
368 echo '==> Starting the generation of the intermediate key pair.'
369 echo '==> This is used to sign server and user certificates.'
370 echo '==> Please fill in the appropriate information asked.'
371 echo ''
372
373 if [ ! -e "$CA_ROOT/intermediate/private/intermediate.key.pem" ]; then
374 # Key
375 echo '=> Generating intermediate key.. Please enter a strong passphrase.'
376 echo ''
377 openssl genrsa -aes256 \
378 -out intermediate/private/intermediate.key.pem 4096
379 else
380 echo '=> Intermediate certificate key exists, skipping..'
381 fi
382
383 if [ ! -e "$CA_ROOT/intermediate/private/intermediate.key.pem" ]; then
384 echo '=x=> Intermediate certificate key was not generated!'
385 return 1
386 fi
387
388 chmod 400 intermediate/private/intermediate.key.pem
389
390 if [ -e "$CA_ROOT/intermediate/csr/intermediate.csr.pem" ]; then
391 rm -f intermediate/csr/intermediate.csr.pem
392 rm -f intermediate/certs/intermediate.cert.pem
393 fi
394
395 # Certificate Signing Request (CSR)
396 echo '=> Generating intermediate CSR..'
397 echo ''
398 openssl req -config "$INTERMEDIATE_ROOT/openssl.cfg" -new -sha256 \
399 -key intermediate/private/intermediate.key.pem \
400 -out intermediate/csr/intermediate.csr.pem
401
402 if [ ! -e "$CA_ROOT/intermediate/csr/intermediate.csr.pem" ]; then
403 echo '=x=> Intermediate signing request was not generated!'
404 return 1
405 fi
406
407 echo '=> Singing the intermediate certificate. Please answer yes in order to continue.'
408 echo ''
409 openssl ca -config "$CA_ROOT/openssl.cfg" -extensions v3_intermediate_ca \
410 -days 3650 -notext -md sha256 \
411 -in intermediate/csr/intermediate.csr.pem \
412 -out intermediate/certs/intermediate.cert.pem
413
414 if [ ! -e "$CA_ROOT/intermediate/certs/intermediate.cert.pem" ]; then
415 echo '=x=> Intermediate certificate was not signed!'
416 return 1
417 fi
418
419 chmod 444 intermediate/certs/intermediate.cert.pem
420
421 # Print info
422 openssl x509 -noout -text \
423 -in intermediate/certs/intermediate.cert.pem
424
425 openssl verify -CAfile certs/ca.cert.pem \
426 intermediate/certs/intermediate.cert.pem
427
428 # Generate Certificate Chain
429 cat intermediate/certs/intermediate.cert.pem \
430 certs/ca.cert.pem > intermediate/certs/ca-chain.cert.pem
431
432 chmod 444 intermediate/certs/ca-chain.cert.pem
433
434 echo '==> Intermediate key pair generated.'
435 echo "==> Your CA (Certificate Authority) is \"$INTERMEDIATE_ROOT/certs/ca-chain.cert.pem\""
436}
437
438createCertificate() {
439 if [ ! -e "$CA_ROOT" ]; then
440 echo "=x=> Certificate root was not found."
441 return 1
442 elif [ ! -e "$INTERMEDIATE_ROOT/openssl.cfg" ]; then
443 echo "=x=> Intermediate certificate configuration was not found."
444 return 1
445 fi
446
447 if [ -z "$1" ]; then
448 echo "=x=> Please provide a name for this certificate."
449 return 1
450 fi
451
452 if [ -z "$2" ] || [ "$2" != "server_cert" ] && [ "$2" != "usr_cert" ]; then
453 echo "=x=> Type must be one of server_cert or usr_cert. If you're unsure about this, use 'usr_cert'."
454 return 1
455 fi
456
457 cd "$CA_ROOT"
458
459 # Custom configuration file
460 local CSRCFG="$INTERMEDIATE_ROOT/openssl.cfg"
461 if [ -n $3 ]; then
462 CSRCFG="$3"
463 fi
464
465 # Generate the key if it does not exist
466 if [ ! -e "$INTERMEDIATE_ROOT/private/$1.key.pem" ]; then
467 echo "==> Generating key for \"$1\""
468 echo ''
469
470 openssl genrsa -out "$INTERMEDIATE_ROOT/private/$1.key.pem" 4096
471 chmod 400 "$INTERMEDIATE_ROOT/private/$1.key.pem"
472
473 if [ ! -e "$INTERMEDIATE_ROOT/private/$1.key.pem" ]; then
474 echo "=x=> Key was not created!"
475 return 1
476 fi
477 fi
478
479 echo "==> Generating CSR for \"$1\""
480 echo ''
481
482 openssl req -config "$CSRCFG" \
483 -key "$INTERMEDIATE_ROOT/private/$1.key.pem" \
484 -new -sha256 -out "$INTERMEDIATE_ROOT/csr/$1.csr.pem"
485
486 if [ ! -e "$INTERMEDIATE_ROOT/csr/$1.csr.pem" ]; then
487 echo "=x=> CSR was not created!"
488 return 1
489 fi
490
491 echo "==> Generating certificate for \"$1\""
492 echo ''
493
494 openssl ca -config "$INTERMEDIATE_ROOT/openssl.cfg" \
495 -extensions "$2" -days 375 -notext -md sha256 \
496 -in "$INTERMEDIATE_ROOT/csr/$1.csr.pem" \
497 -out "$INTERMEDIATE_ROOT/certs/$1.cert.pem"
498
499 if [ ! -e "$INTERMEDIATE_ROOT/certs/$1.cert.pem" ]; then
500 echo "=x=> Certificate was not created!"
501 return 1
502 fi
503
504 chmod 444 "$INTERMEDIATE_ROOT/certs/$1.cert.pem"
505
506 echo "==> Done."
507 echo "==> Key: $INTERMEDIATE_ROOT/private/$1.key.pem"
508 echo "==> Cert: $INTERMEDIATE_ROOT/certs/$1.cert.pem"
509}
510
511revokeCertificate() {
512 if [ ! -e "$CA_ROOT" ]; then
513 echo "=x=> Certificate root was not found."
514 return 1
515 elif [ ! -e "$INTERMEDIATE_ROOT/openssl.cfg" ]; then
516 echo "=x=> Intermediate certificate configuration was not found."
517 return 1
518 fi
519
520 if [ -z "$1" ]; then
521 echo "=x=> Please provide a name for a certificate to revoke."
522 return 1
523 fi
524
525 cd "$CA_ROOT"
526
527 echo "==> Revoking certificate"
528
529 openssl ca -config "$INTERMEDIATE_ROOT/openssl.cfg" \
530 -revoke "$INTERMEDIATE_ROOT/certs/$1.cert.pem"
531
532 echo "==> Done."
533}
534
535printInfo () {
536 if [ ! -e "$CA_ROOT" ]; then
537 echo "=x=> Certificate root was not found."
538 return 1
539 elif [ ! -e "$INTERMEDIATE_ROOT/openssl.cfg" ]; then
540 echo "=x=> Intermediate certificate configuration was not found."
541 return 1
542 fi
543
544 if [ -n "$1" ]; then
545 openssl x509 -noout -text -in "$CA_ROOT/intermediate/certs/$1.cert.pem"
546 return 0
547 fi
548
549 echo "=> Root certificate"
550 openssl x509 -noout -text -in "$CA_ROOT/certs/ca.cert.pem"
551
552 echo "=> Intermediate certificate"
553 openssl x509 -noout -text \
554 -in "$CA_ROOT/intermediate/certs/intermediate.cert.pem"
555
556 openssl verify -CAfile "$CA_ROOT/certs/ca.cert.pem" \
557 "$CA_ROOT/intermediate/certs/intermediate.cert.pem"
558
559 echo ""
560 echo "==> Paths"
561 echo "Root: $CA_ROOT"
562 echo "Intermediate: $CA_ROOT/intermediate"
563 echo ""
564
565 echo "Root Key: $CA_ROOT/private/ca.key.pem"
566 echo "Root Cert: $CA_ROOT/certs/ca.cert.pem"
567
568 echo "CA Key: $CA_ROOT/intermediate/private/intermediate.key.pem"
569 echo "Chain: $CA_ROOT/intermediate/certs/ca-chain.cert.pem"
570 echo ""
571}
572
573printHelp () {
574 echo "Usage: ./ca <CA Path> info | wizard | root | intm | revoke [<name>] | new [<name>] [ server_cert | usr_cert ] [ openssl.cfg ]"
575 echo -e " info\t- Print information about your CA"
576 echo -e " wizard\t- Create a new CA"
577 echo -e " root\t- Generate root certificate. For use when wizard fails."
578 echo -e " intm\t- Generate intermediate certificate. For use when wizard fails."
579 echo -e " new \t- Create a new certificate signed with your CA. Can also be used for renewal."
580 echo -e " revoke\t- Revoke a certificate by name"
581}
582
583set -e
584case "$2" in
585 "info")
586 printInfo $3
587 ;;
588 "wizard" | "generate" | "newca")
589 echo "==> Proceeding with full generation for path $1"
590 deployFiles
591 generateRootPair
592 generateIntermediate
593 printInfo
594 ;;
595 "files")
596 deployFiles
597 ;;
598 "rootpair" | "root")
599 generateRootPair
600 ;;
601 "intermediate" | "intm")
602 generateIntermediate
603 ;;
604 "certificate" | "cert" | "new" | "renew")
605 createCertificate $3 $4 $5
606 ;;
607 "revoke")
608 revokeCertificate $3
609 ;;
610 "help")
611 printHelp
612 ;;
613 *)
614 echo "Usage: ./ca <CA Path> info | wizard | root | intm | revoke [<name>] | new [<name>] [ server_cert | usr_cert ] [ openssl.cfg ]"
615 ;;
616esac
617