-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmk-cert
executable file
·2082 lines (1739 loc) · 53.9 KB
/
mk-cert
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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/bin/sh
# shellcheck shell=bash disable=SC2230
if [ -z "$BASH_VERSION" ];then exec bash "$0" "$@";else set +o posix;fi
(eval 'f() { local i=$((3+(6)));[[ $i = "$(cat <(echo 9))" ]];};f')\
2>/dev/null || { echo >&2 "This version of bash is too old";exit 1;}
set -e ; PROGRAM="$0"
show_help_text() {
echo "Usage: $(basename "$PROGRAM") [Common Name] [arguments]"
version_warnings
cat <<\!
This script can create most styles of x509 certificate from the command
line. All options can be configured from arguments and the standard
OpenSSL configuration file is not used. The default is to prompt for a
common name (plus OU and dnQualifier) and generate an ec:prime256r1 key
and certificate which is sent to the standard output.
Options:
-cn=String
-subj-cn=String
-subj-ou=String
-subj-dc=String
-subj-o=String
-subj-l=String
-subj-st=String
-subj-c=String
-subj:oid=value
Set a component of the certificate subject. Some items such as
DC, OU and CN are allowed to be duplicated. OpenSSL will accept
duplicates for any item.
The OU is the most likely to be accepted as a place to store
any unusual part of a name you may wish to include.
The "-cn=" option is taken as both a common name, a SAN and the
official common name for generic use. The "-subj-cn=" option
string will only be used in the subject.
Any arguments without a "-" to make them an option are assumed
to be names too, the first one is a common name, like the "-cn"
option. The rest are san names if they look like domain names
or IP addresses and OU items if they don't.
If a argument begins with a "/" and contains an "=" it is
treated as an OpenSSL subject string. This conflicts with the
other options for building a subject.
The bare "-subj:" version copies the string "oid=value" to the
end of the section of the configuration. This allows any of the
possible name parts (surname, info, favouriteDrink, CSPName, etc)
to be added in any order. If OpenSSL doesn't know a particular
oid the numeric value can be used.
If no subject is specified one will be prompted for by OpenSSL
unless a SAN is requested in which case an error is generated
unless "-no-prompt" is used.
-days=7304
How many days should the certificate run for?
-days=2038-01-18
What day should the certificate expire on?
-alldays
Make the certificate run until 9999-12-31
-out=FileName
Put the certificate, and any other items in a file.
-addcert=FileName
Filename contains a certificate, put it in the same location as
the created certificate. (Used for intermediate CA certificates)
-keyout=FileName
Put the private key in a specific file not "-out=" or stdout.
-crl
Generate an empty CRL using the certificate used to sign.
-crlout=FileName
Generate an empty CRL using the certificate used to sign.
-caout=FileName
Put the certificate used to sign in a specific file.
-ser=0123456789abcdef
-serial=0123456789abcdef
Set the certificate serial number (in hexadecimal).
Various noise characters will be removed.
-dnq
Generate and add a dnQualifier item to the subject.
This is the original way of making sure that the subject of
a certificate is unique. It was only needed within an org
as the other DN components were sufficient for identifing
organisations.
-dnq=...
Add a specific dnQualifier item to the subject.
-nodnq
Do not add a dnQualifier item to any subject; even if told to.
-no-prompt
Prevent OpenSSL prompting for any part of the subject.
-ec:prime256v1
-ec:256
-ec:curve:encoding
-ec:curve:encoding:no_seed
-ec:ed25519
Use OpenSSL ecparam to generate an EC key. This includes ed25519, ed448
and their X25519 and X448 counterparts. The numbers 256,384 and 521 are
shorthands for the curves prime256v1, secp384r1 and secp521r1.
-ed25519
-ed448
Generate an ed25519 or ed448 private key.
-list-curves
-show-curves
List the EC curves that OpenSSL supports.
-rsa
-rsa=2048
Generate RSA private keys.
-dsa
-dsa=1024
Generate DSA private keys.
NB: This also makes the default digest SHA1.
-keyfile=FileName
Don't generate a key, use the one in FileName. If you're generating
a "single use ca" the second throwaway key will be generated to be
the same type as the key in this file if possible.
-csrin=FileName
Use the CSR from FileName instead of generating a new key.
This cannot be used to create a self-signed certificate.
-pubin=FileName
Like -csrin this will use the public key from the item in FileName
instead of generating a new key. The file can be any recognised
file that contains a public key, not just a CSR. But if it's
a CSR or a certificate it's common name will also be used if
nothing else is specified.
-csr
Create a certificate signing request not a certificate
Must use -keyout= option too.
-showcsr
Dump any CSR we use to the output too.
-sign=FileName
Use the key and certificate in FileName to sign the certificate,
note if it's a PFX file it must have a ".pfx" extension.
-singleuseca
-suca
Generate a new CA key for the CA certificate and to sign the standard
certificate. Discard the CA key and send the CA certificate to the
output.
-v3singleuseca
-v3suca
Same but always make the CA a V3 certificate with the CA flag.
-v1suca
Same but always make the CA a V1 certificate.
-casubj=...
-caname=...
Set the subject name for the single use CA, first is a CN or
organisation, the rest are OU items.
-pkcs12=FileName
-pfx=FileName
Create a "pfx" file with the certificate, private key and the
CA certificate used to sign the certificate. The "-pkcs12" variant
saves the file base64 encoded.
-pass:password
-pass=OpenSSL:pass
Set a password on the key.
-cipher=name
Select the cipher used for encrypting the key with a password.
-dgst=sha1
-ripemd160, -sha, -sha1, -sha224, -sha256, -sha384, -sha512, -whirlpool
Select the digest used for signing.
-openssl=/path/to/executable/openssl
Use the specified copy of openssl, not the one in the PATH.
-showconf
Debugging option, show the config files generated for OpenSSL
Version 3 certificate extensions.
Note V3 extensions are used to limit the uses that a certificate
can be put to. If you're not concerned with limiting use of the
private key (ie the user is trusted) then these generally have
no use. However, some validators insist on certain V3 extensions
being present.
The SAN extension is a minor exception to this as it allows multiple
wildcard DNS names whereas browsers only accept one wildcard CN
item in the subject. In addition some browsers are rejecting all
certificates that don't have a SAN extension.
-v3
Make the certificate V3, don't add any extensions though.
-v3san=SanName
-san=SanName
Add a SAN name.
It may include the type prefix ie: DNS:www.example.com otherwise
a dumb huristic is used to identify the type of the item. This
option can be repeated as many times as needed.
Note: the common name will normally be added automatically too.
-v3san, -san
Make a san from the common name even if there are no others.
This is now required by Chrome in direct contravention of the
requirements of RFC 2818 (HTTP over SSL).
-v3ca, -ca
Add normal V3 extensions for a CA certificate.
-v3basicca
Add only the basic extension for a CA certificate.
-v3lastca, -lastca
Make a V3 CA certificate with the 'pathlen:0' option to prevent
certificates that this CA signs being CAs.
-v3nokeyid, -nokeyid
Disable the "Subject Key Identifier" and "Authority Key Identifier"
additions.
-v3usr, -v3user, -usr, -user
Prevent this V3 certificate begin used as a CA.
-v3server, -server
Add V3 key usage extensions to prevent the certificate being used
as anything except an SSL server.
NB: Can be combined with -v3client or -v3email to allow those.
-v3client, -client
Add V3 key usage extensions to prevent the certificate being used
as anything except an SSL client.
NB: Can be combined with -v3server or -v3email to allow those.
-v3email, -email
Add V3 key usage extensions to prevent the certificate being used
as anything except a MIME signing or encryption certificate.
NB: Can be combined with -v3server or -v3client to allow those.
-v3codesign, -codesign
Add V3 key usage extensions to prevent the certificate being used
as anything except a code signing certificate.
-v3timestamp, -timestamp
Add V3 key usage extensions for timestamp signing. This can NOT
be combined with other key usages.
-v3ns, -ns
Add the netscape Client/server extensions too.
-v3ns=...
-ns=...
Add a specific list of netscape usages.
-v3crit, -v3critical, -critical
Mark CA, key usage and extended key usage extensions as critical.
Beware:
https://en.wikipedia.org/wiki/X.509#Implementation_issues
-poltext=FileName
Add an "all uses" policy extension and include the text from
FileName as an "issuer statement".
-policy=OID
The first one of these sets the OID for the '-poltext' option if
present. Additional '-policy' arguments add extra policy extensions.
-tlsfeature=...
Add the V3 extension that states a server will send a 'status_request'
or 'status_request_v2' response when requested.
-must-staple
Alias for -tlsfeature=status_request
Can also be entered as -v3=1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05
-v3permit=..., -permit=..., -v3exclude..., -exclude...
Add the V3 extension for 'Name constraints', they consist of domain
names or IP addresses with subnet masks in the form of tagged SAN
names.
-v3crluri=..., -crlurl=...
Add a "CRL Distribution Point" item to the certificate extensions.
-v3dv|-dv )
Make the certificate policy "Domain validated" and set most
of the other stuff that's supposed to be set.
BUT would also need:
The certificate must be signed by a CA (not self-signed)
Add authorityInformationAccess extension
with OCSP over HTTP
and HTTP URL for issuing certificate
-v3='OpenSSL extension config'
Add any x509 v3 extension config to the OpenSSL config file used
to create the certificate.
-v3xt='OpenSSL extension config'
-xt='OpenSSL extension config'
Add any x509 v3 extension config to the OpenSSL config file used
to create the certificate.
This item is placed after the all "-v3=" items so can be used when
the config file needs additional sections.
!
exit 0
}
version_warnings() {
[[ "$BASH3" = yes || "$NOMIXING" = yes || "$BASHREGEX" = no ]] && {
echo ""
echo "BEWARE: Some features are broken or work poorly on this version"
echo "of bash: $BASH_VERSION"
}
[[ "$NOPKEY" = yes || "$NOECPARAM" = yes ]] && {
echo ""
echo "BEWARE: Some features are broken or work poorly on this version"
echo "of openssl: $(openssl version)"
}
return 0
}
main() {
eval "typeset -A SANDUP # bash4/ksh" 2>/dev/null && BASH3=no || BASH3=yes
init_vars
test_for_windows
decode_args "$@"
default_options
check_args
[[ "$KFN" != '' && "$KFN" != /dev/null && -s "$KFN" ]] &&
{ echo >&2 "ERROR: File $KFN already exists" ; exit 1 ; }
[[ "$FN" != '' && -s "$FN" ]] &&
{ echo >&2 "ERROR: File $FN already exists" ; exit 1 ; }
[[ "$CAFN" != '' && -s "$CAFN" ]] &&
{ echo >&2 "ERROR: File $CAFN already exists" ; exit 1 ; }
[[ "$PKCS12FN" != '' && -s "$PKCS12FN" ]] &&
{ echo >&2 "ERROR: File $PKCS12FN already exists" ; exit 1 ; }
[[ "$CRLFN" != '' && -s "$CRLFN" ]] &&
{ echo >&2 "ERROR: File $CRLFN already exists" ; exit 1 ; }
build_v3_extensions
apply_options
create_main_cert # or csr
create_suca_pem
if [[ "$CSRFN" != "" && "$SIGNPEM" = '' ]]
then echo 'ERROR: Cannot make a self signed certificate from a csr' >&2
exit 1;
fi
if [[ "$FORCEPUB" != "" && "$SIGNPEM" = '' ]]
then echo 'ERROR: Cannot make a self signed certificate from a public key' >&2
exit 1;
fi
sign_created_csr
[[ "$MAKECRL" = yes ]] &&
CRLPEM=$(create_crl_file)
create_pfx_file
[[ "$KFN" = '' ]] && umask 077
# shellcheck disable=SC2094 # ironic.
if [[ "$FN" != '' ]] ; then outp "$FN" > "$FN" ; else outp ; fi
exit 0
}
init_vars() {
NL='
'
export OPENSSL_CONF=/dev/null
NOPKEY="$(openssl no-pkey >/dev/null 2>&1 && echo yes || echo no)"
NOECPARAM="$(openssl no-ecparam >/dev/null 2>&1 && echo yes || echo no)"
NOMIXING="$(eval 'x=1;[ "$(set -- ${x:+0 "$x"} 2;echo "$2")" = "1" ]' && echo no || echo yes)"
FN=
KFN=
ADDCERT=
CRLFN=
CSRFN=
PUBKEYFN=
PUBDATA=
CAFN=
FORCEPUB=
SERIAL=
CERT_DAYS=
EC=prime256v1
RSABITS=2048
# shellcheck disable=SC2046 # I knooow
JTODAY=$(jdayjdat $(date '+%d %m %Y') )
if [[ "$NOPKEY" = no ]] || \
[[ "$(date +%Y -d @$((2**31)) 2>/dev/null)" = 2038 ]]
then DEFAULT_DAYS=7304
else
# Older versions have a date bug on 32bit machines.
END_OF_TIME=$(jdayjdat 18 1 2038)
DEFAULT_DAYS=$((END_OF_TIME - JTODAY))
# Minimum of 10 years
[[ "$DEFAULT_DAYS" -lt 3652 ]] &&
DEFAULT_DAYS=3652
fi
V3=no
V3HEAD=
V3SAN=
V3OPTS=
V3LIST=
V3EXTRAS=
V3CERTONLY=
V3CA=
V3CAPATH=
V3CLIENT=no
V3SERVER=no
V3EMAIL=no
V3CODESIGN=no
V3TIMESTAMP=no
V3CRITICAL=no
V3NS=no
V3ENS=
V3NAMECONS=
SANSECT=
SAN_ID=0
BASHREGEX=
NOSETSERIAL=
KEYPASS=
WANTCSR=no
MAKECSR=no
ADDDNQ=
SHOWCSR=no
MAKECRL=no
SHOWCONF=
CSRTEXT=
SIGNPFX=
SIGNPEM=
CRLPEM=
SINGLEUSECA=
V3SUCA=
PKCS12FN=
PKCS12ASCII=
POLICYTEXT=
POLICYOID=
NOPROMPT=
NOKEYID=
WANTDVCERT=
DEFAULTCN=
TLSFEATURE=
NOSUCAEKU=
CIPHER=-aes128
DGST=
SUBJTYPE=
SUBJ=
CASUBJ=
SUBJ_ID=0
SUBJ_C=
SUBJ_ST=
SUBJ_L=
SUBJ_O=
SUBJ_DC=
SUBJ_OU=
SUBJ_CN=
SUBJ_DNQ=
SUBJ_XX=
CRLURI=
CRLURI_ID=0
EXTRA_OIDS=
SSKEY=
# Faketime prefix
ft() { "$@" ; }
# This is my default for making a key file.
# Versions before "pkey" didn't do EC+SHA256
if [[ "$NOECPARAM" = no && "$NOPKEY" = no ]]; then
mkkey() { openssl ecparam -name "$EC" -genkey -noout ;}
mktmpkey() { openssl ecparam -name "$EC" -genkey -noout ;}
KEYCLASS=ec
else
mkkey() { openssl genrsa $RSABITS ; }
mktmpkey() { openssl genrsa 512 2>/dev/null ; }
KEYCLASS=rsa
fi
KEYSOURCE=
# See also:
# mkkey() { openssl genpkey -paramfile <(openssl genpkey -genparam -algorithm ec -pkeyopt ec_paramgen_curve:prime256v1) ;}
X509SECT=req_x509
V3INIT="x509_extensions=$X509SECT${NL}req_extensions=$X509SECT${NL}[$X509SECT]${NL}"
UTF8=
if [[ "$(locale charmap 2>/dev/null)" = UTF-8 ]]
then
if openssl req -help 2>&1 | grep -q -e -utf8
then UTF8=-utf8
fi
fi
}
decode_args() {
for ar
do case "$ar" in
-h|-help|--help) show_help_text ;;
-showconf ) SHOWCONF=yes ;;
-days ) CERT_DAYS='' ;;
-alldays ) CERT_DAYS=all ;;
-days[=:]* ) CERT_DAYS="${ar#*[=:]}" ;;
-out[=:]* ) FN="${ar#*[=:]}" ;;
-keyout[=:]* ) KFN="${ar#*[=:]}" ;;
-crl ) MAKECRL=yes ;;
-crlout[=:]* ) CRLFN="${ar#*[=:]}" ; MAKECRL=yes ;;
-caout[=:]* ) CAFN="${ar#*[=:]}" ;;
-ser[=:]??*|-serial[=:]??* )
SERIAL="${ar#*[=:]}"
SERIAL="${SERIAL//[-: .,;]/}"
;;
-dnq ) [[ "$ADDDNQ" = no ]] || ADDDNQ=yes ;;
-nodnq|-no-dnq ) ADDDNQ=no ;;
-dnq[=:]*|-cn[=:]* )
SUBJTYPE="${SUBJTYPE:-conf}"
if [[ "$SUBJTYPE" != "conf" ]] ; then
echo >&2 "Duplicate subject name definition at '$ar'"; exit 1
fi
case "$ar" in
-dnq* )
SUBJ_ID=$((SUBJ_ID+1))
SUBJ_DNQ="$SUBJ_DNQ${NL}$SUBJ_ID.dnQualifier=${ar#*[=:]}"
;;
-cn* )
if [[ "${ar#*[=:]}" != '' ]]
then SUBJ_ID=$((SUBJ_ID+1))
SUBJ_CN="$SUBJ_CN${NL}$SUBJ_ID.commonName=${ar#*[=:]}"
else SUBJ_CN="$SUBJ_CN${NL}"
fi
NOPROMPT=yes
if [[ "$CN" = '' ]]
then CN="${ar#*[=:]}"
else add_good_san "${ar#*[=:]}" ||:
fi
;;
esac
;;
-rsa[=:]* )
KEYCLASS=rsa
KEYSOURCE="$KEYSOURCE:rsa"
eval "mkkey() { openssl genrsa '${ar#*[=:]}' ; }"
;;
-dsa[=:]* )
KEYCLASS=
KEYSOURCE="$KEYSOURCE:dsa"
eval "mkkey() { openssl dsaparam -noout -genkey '${ar#*[=:]}' ; }"
;;
-ec[=:]* )
[[ "$NOECPARAM" = no ]] || {
echo >&2 "Elliptic Curve keys not supported by OpenSSL"
exit 1
}
ar="${ar#*[=:]}:" ; curve="${ar%%:*}"
ar="${ar#*:}:" ; param="${ar%%:*}"
ar="${ar#*:}:" ; noseed="${ar%%:*}"
case "$curve" in
192 ) curve=prime192v1 ;;
224 ) curve=secp224r1 ;;
256 ) curve=prime256v1 ;;
384 ) curve=secp384r1 ;;
521 ) curve=secp521r1 ;;
[0-9]*[0-9] )
ncurve="$(openssl ecparam -list_curves| grep " $curve bit" |
awk -F: '/:/{print $1;exit;}' | tr -d ' ' )"
[[ "$ncurve" != "" ]] && curve="$ncurve"
;;
esac
case "$curve" in
X25519|x25519|X448|x448 )
echo >&2 "WARNING: The ${curve} EC algorithm cannot do signatures, did you mean the ED version?"
KEYCLASS=nosig
KEYSOURCE="$KEYSOURCE:X"
SSKEY=$(openssl genpkey -algorithm "$curve")
PUBDATA=$(echo "$SSKEY" | openssl pkey -pubout)
eval "mkkey() { openssl genpkey -algorithm 'ed${curve#?}' ; }"
;;
ED25519|ed25519|ED448|ed448 )
eval "mkkey() { openssl genpkey -algorithm '${curve}' ; }"
KEYCLASS=
KEYSOURCE="$KEYSOURCE:ed"
;;
*)
eval "mkkey() { openssl ecparam -name '$curve' ${param:+-param_enc $param} ${noseed:+-no_seed} -genkey -noout ; }"
KEYCLASS=ec
KEYSOURCE="$KEYSOURCE:ec"
;;
esac
;;
-ED25519|-ed25519|-ED448|-ed448 )
eval "mkkey() { openssl genpkey -algorithm '${ar#?}' ; }"
KEYCLASS=
KEYSOURCE="$KEYSOURCE:ed"
;;
-dsa )
# FIPS used to force 1024, so lots of hardware and protocols did too.
# 1024 bits is now considered unsafe against the most capable
# attackers and barely safe against publicly known attacks.
DGST="${DGST:--sha1}"
mkkey() { openssl dsaparam -noout -genkey 1024; }
KEYCLASS=
KEYSOURCE="$KEYSOURCE:dsa"
;;
-rsa )
mkkey() { openssl genrsa $RSABITS ; }
KEYCLASS=rsa
KEYSOURCE="$KEYSOURCE:rsa"
;;
-ec )
[[ "$NOECPARAM" = no ]] || {
echo >&2 "Elliptic Curve keys not supported by OpenSSL"
exit 1
}
mkkey() { openssl ecparam -name "$EC" -genkey -noout ; }
KEYCLASS=ec
KEYSOURCE="$KEYSOURCE:ec"
;;
-list[-_]curves|-show[_-]curves )
openssl ecparam -list_curves ; exit ;;
-keyfile[=:]*|-key[=:]* )
eval "mkkey() { cat < '${ar#*[=:]}' ; }"
[[ "$KFN" = "" ]] && KFN=/dev/null
KEYCLASS='file'
KEYSOURCE="$KEYSOURCE:keyfile"
;;
-csr ) WANTCSR=yes ; MAKECSR=yes ;;
-csrin[=:]* )
CSRFN="${ar#*[=:]}"
KFN=/dev/null
KEYCLASS=
KEYSOURCE="$KEYSOURCE:csr"
;;
-showcsr ) SHOWCSR=yes ;;
-pubin[=:]* )
PUBKEYFN="${ar#*[=:]}"
KFN=/dev/null
KEYCLASS=
KEYSOURCE="$KEYSOURCE:pubkey"
;;
-sign[=:]*.pfx )
SIGNPFX="${ar#*[=:]}"
MAKECSR=yes
;;
-sign[=:]* )
SIGNPEM="$(cat "${ar#*[=:]}")"
MAKECSR=yes
;;
-addcert[=:]* )
[[ "$ADDCERT" != '' ]] && ADDCERT="$ADDCERT$NL"
ADDCERT="$ADDCERT$(
openssl x509 -subject -serial -dates -in "${ar#*[=:]}"
)"
;;
-singleuseca|-suca ) MAKECSR=yes ; SINGLEUSECA=yes ;;
-v1suca ) MAKECSR=yes ; SINGLEUSECA=yes ; V3SUCA=no ;;
-v3singleuseca|-v3suca ) MAKECSR=yes ; SINGLEUSECA=yes ; V3SUCA=yes ;;
-nocaeku ) NOSUCAEKU=yes ;;
-pfx[=:]* )
PKCS12FN="${ar#*[=:]}"
[[ "$FN" = "" ]] && FN=/dev/null
# Default PFX files to RSA
[ "$KEYSOURCE" = '' ] && {
mkkey() { openssl genrsa $RSABITS ; }
KEYCLASS=rsa
}
;;
-pkcs12[=:]* )
PKCS12FN="${ar#*[=:]}"
[[ "$FN" = "" ]] && FN=/dev/null
PKCS12ASCII=yes
# Default PFX files to RSA
[ "$KEYSOURCE" = '' ] && {
mkkey() { openssl genrsa $RSABITS ; }
KEYCLASS=rsa
}
;;
-pass[=:]*:* ) KEYPASS="${ar#*[=:]}" ;;
-pass[=:]* ) KEYPASS="pass:${ar#*[=:]}" ;;
-ripemd160|-sha|-sha1|-sha224|-sha256|-sha384|-sha512|-whirlpool)
DGST=$ar ;;
-dgst[=:]* ) DGST="${ar#*[=:]}" ; DGST="-${DGST%-}" ;;
-cipher[=:]* ) CIPHER="${ar#*[=:]}" ; CIPHER="-${CIPHER%-}" ;;
-openssl[:=]* ) eval "openssl() { command '${ar#*[=:]}' \"\$@\" ; }" ;;
-v3 ) V3=yes ;;
-v3ca|-ca ) V3=yes ; V3CA=yes ;;
-v3lastca|-lastca ) V3=yes ; V3CA=yes ; V3CAPATH=0 ;;
-v3usr|-usr|-v3user|-user ) V3=yes ; V3CA=no ;;
-v3server|-server ) V3=yes ; V3SERVER=yes ;;
-v3client|-client ) V3=yes ; V3CLIENT=yes ;;
-v3email|-email ) V3=yes ; V3EMAIL=yes ;;
-v3codesign|-codesign ) V3=yes ; V3CODESIGN=yes ;;
-v3timestamp|-timestamp ) V3=yes ; V3TIMESTAMP=yes ; V3CRITICAL=yes ;;
-v3crit|-v3critical|-critical )
V3=yes ; V3CRITICAL=yes ; V3CA=${V3CA:-no}
;;
-v3nokeyid|-nokeyid|-no-keyid) NOKEYID=yes ;;
-v3basicca )
V3=yes
V3LIST="$V3LIST${NL}basicConstraints = CA:TRUE"
;;
-v3policytext[=:]*|-policytext[=:]*|-poltext[=:]* )
V3=yes
POLICYTEXT="$(cat "${ar#*[=:]}")"
;;
-v3policy[=:]*|-policy[=:]* )
V3=yes
POLICYOID="$POLICYOID,${ar#*[=:]}"
;;
-v3ns|-ns ) V3=yes ; V3NS=yes ;;
-v3ns[=:]*|-ns[=:]* )
V3=yes
V3NS=yes
V3ENS="${ar#*[=:]}"
;;
-v3[=:]* )
V3=yes
V3LIST="$V3LIST$NL${ar#*[=:]}"
;;
-v3xt[=:]*|-xt[=:]* )
V3=yes
V3EXTRAS="$V3EXTRAS$NL${ar#*[=:]}$NL"
;;
-v3san[=:]*|-san[=:]* )
if ! add_good_san "${ar#*[=:]}"
then
san="${ar#*[=:]}"
case "$san" in
[0-9a-fA-F]*:*:*[0-9a-fA-F]|::*[0-9a-fA-F] )
add_san "IP:$san" ;;
*@* ) add_san "email:$san" ;;
*[:-?]*|*[0-9]|[0-9]* )
echo "Undecidable san name '$san', please label" >&2
exit 1
;;
* ) add_san "DNS:$san" ;;
esac
fi
;;
-v3san|-san ) V3=yes ; V3SAN=yes ;;
-v3tlsfeature[=:]*|-tlsfeature[=:]*|-must-staple )
V3=yes
if [[ "$TLSFEATURE" = '' ]]
then TLSFEATURE='tlsfeature = '
else TLSFEATURE="$TLSFEATURE,"
fi
FEATURE="${ar#*[=:]}"
[[ "$FEATURE" = "-must-staple" || "$FEATURE" = "must-staple" ]] &&
FEATURE=status_request
TLSFEATURE="$TLSFEATURE$FEATURE"
;;
-v3permit[=:]*|-permit[=:]* )
add_name_constraint "${ar#*[=:]}" permitted
;;
-v3exclude[=:]*|-exclude[=:]* )
add_name_constraint "${ar#*[=:]}" excluded
;;
-v3crlur[il][=:]*|-crlur[il][=:]* )
V3=yes
CRLURI_ID=$((CRLURI_ID+1))
CRLURI="$CRLURI${NL}URI.$CRLURI_ID=${ar#*[=:]}"
;;
-v3dv|-dv )
# Make the certificate policy "Domain validated" and set most
# of the other stuff that's supposed to be set.
# BUT would also need:
# Add authorityInformationAccess extension
# with OCSP over HTTP extension
# and HTTP URL for issuing certificate
#
# For example:
# -v3='authorityInfoAccess = OCSP;URI:http://ocsp.my.host/,caIssuers;URI:http://my.ca/ca.html'
#
# In addition the commonName is "deprecated",
# but all public CA's still include it.
WANTDVCERT=yes
V3=yes
V3SAN=yes
V3SERVER=yes
V3CLIENT=yes
V3CRITICAL=yes
POLICYOID="$POLICYOID,2.23.140.1.2.1"
DEFAULT_DAYS=398
;;
/*=* )
if [[ "$SUBJTYPE" != "" ]] ; then
echo >&2 "Duplicate subject name definition at '$ar'"; exit 1
fi
SUBJ="$ar"
SUBJTYPE=arg
;;
-noprompt|-no-prompt ) NOPROMPT=yes ;;
-subj[-_]c[=:]*|-subj[-_]st[=:]*|-subj[-_]l[=:]*|-subj[-_]o[=:]*|\
-subj[-_]dc[=:]*|-subj[-_]ou[=:]*|-subj[-_]cn[=:]* )
SUBJTYPE="${SUBJTYPE:-conf}"
if [[ "$SUBJTYPE" != "conf" ]] ; then
echo >&2 "Duplicate subject name definition at '$ar'"; exit 1
fi
V="${ar#??????}"
C="${V/=*/}"
# shellcheck disable=SC2018,SC2019
C="$(echo "$C" | tr 'a-z' 'A-Z')"
SUBJ_ID=$((SUBJ_ID+1))
eval "SUBJ_$C=\"\$SUBJ_$C\${NL}\$SUBJ_ID.$C=\${ar#*[=:]}\""
;;
-subj[=:]* )
SUBJTYPE="${SUBJTYPE:-conf}"
if [[ "$SUBJTYPE" != "conf" ]] ; then
echo >&2 "Duplicate subject name definition at '$ar'"; exit 1
fi
V="${ar#*[=:]}"
V1="${V/=*/}"
V2="${V#*=}"
case "$V1" in
[0-9]*.*[0-9] ) # Looks kinda like an OID ?
V3="oid_${V1//./_}"
EXTRA_OIDS="$EXTRA_OIDS$NL$V3=$V1"
SUBJ_XX="$SUBJ_XX$NL$V3=$V2"
;;
* ) SUBJ_XX="$SUBJ_XX$NL$V"
;;
esac
SUBJ_ID=$((SUBJ_ID+1))
;;
-casubj[=:]*|-caname[=:]* )
V="${ar#*[=:]}"
case "$V" in
*\ * ) CASUBJ="${CASUBJ}O=$V${NL}" ;;
* ) if [[ "$CASUBJ" = '' ]]
then CASUBJ="CN=$V${NL}"
else CASUBJ="${CASUBJ}OU=$V${NL}"
fi
;;
esac
;;
-*) echo >&2 "Unknown option: $ar, use -help for help text." ; exit 1 ;;
* ) SUBJTYPE="${SUBJTYPE:-conf}"
if [[ "$SUBJTYPE" != "conf" ]] ; then
echo >&2 "Duplicate subject name definition at '$ar'"; exit 1
fi
if [[ "$ar" = "" ]]
then SUBJ_CN="$SUBJ_CN${NL}"
NOPROMPT=yes
elif [[ "$SUBJ_CN" = "" ]]
then SUBJ_ID=$((SUBJ_ID+1))
SUBJ_CN="$SUBJ_CN${NL}${SUBJ_ID}.CN=$ar"
CN="$ar"
else
add_good_san "$ar" || {
SUBJ_ID=$((SUBJ_ID+1))
SUBJ_OU="$SUBJ_OU${NL}${SUBJ_ID}.OU=$ar"
}
fi
;;
esac
done
return 0
}
# Bash regex's are conditional so we can still mostly work on V2 bash.
if (eval 'x=1.12.123;[[ "$x" =~ ^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})$ ]]') \
2>/dev/null
then
BASHREGEX=yes
eval "$(cat <<\!
add_good_san() {
local san=
if [[ "$1" =~ ^(IP|DNS|email|URI|RID|dirName): ]]
then san="$1"
elif [[ "$1" =~ ^otherName:.*\;.*: ]]
then san="$1"
elif [[ "$1" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]
then san="IP:$1"
elif [[ "$1" =~ ^(\*\.)?([a-zA-Z][-a-zA-Z0-9]*\.)*[a-zA-Z][-a-zA-Z0-9]+$ ]]
then san="DNS:$1"
fi
[[ "$san" = '' ]] && return 1
add_san "$san" ${2:+"$2"}
}
add_name_constraint() {
local san=
if [[ "$1" =~ ^(IP|DNS|email|URI|RID|dirName): ]]
then san="$1"
elif [[ "$1" =~ ^otherName:.*\;.*: ]]
then san="$1"
elif [[ "$1" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]
then san="IP:$1"
elif [[ "$1" =~ ^(\*\.)?([a-zA-Z][-a-zA-Z0-9]*\.)*[a-zA-Z][-a-zA-Z0-9]+$ ]]
then san="DNS:$1"
fi
[[ "$san" = '' ]] && {
echo >&2 "Cannot guess '$1', please tag it"
exit 1
}