diff options
author | job <> | 2024-01-26 11:58:37 +0000 |
---|---|---|
committer | job <> | 2024-01-26 11:58:37 +0000 |
commit | ebf8195ae2a041b9e833b4a53bdf3b0f0ac2fee7 (patch) | |
tree | 22591d8d23256836bf7d611b624a079dc6dafe19 /src | |
parent | e71abd74fd0206dc7a48c9c5a889e557b2afbb45 (diff) | |
download | openbsd-ebf8195ae2a041b9e833b4a53bdf3b0f0ac2fee7.tar.gz openbsd-ebf8195ae2a041b9e833b4a53bdf3b0f0ac2fee7.tar.bz2 openbsd-ebf8195ae2a041b9e833b4a53bdf3b0f0ac2fee7.zip |
Add 'openssl x509 -new' functionality to the libcrypto CLI utility
The ability to generate a new certificate is useful for testing and
experimentation with rechaining PKIs.
While there, alias '-key' to '-signkey' for compatibility.
with and OK tb@
Diffstat (limited to 'src')
-rwxr-xr-x | src/regress/usr.bin/openssl/appstest.sh | 51 | ||||
-rw-r--r-- | src/usr.bin/openssl/openssl.1 | 23 | ||||
-rw-r--r-- | src/usr.bin/openssl/x509.c | 62 |
3 files changed, 121 insertions, 15 deletions
diff --git a/src/regress/usr.bin/openssl/appstest.sh b/src/regress/usr.bin/openssl/appstest.sh index 500fae0251..8c0e75deb4 100755 --- a/src/regress/usr.bin/openssl/appstest.sh +++ b/src/regress/usr.bin/openssl/appstest.sh | |||
@@ -1,6 +1,6 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | # | 2 | # |
3 | # $OpenBSD: appstest.sh,v 1.60 2024/01/12 13:16:48 tb Exp $ | 3 | # $OpenBSD: appstest.sh,v 1.61 2024/01/26 11:58:36 job Exp $ |
4 | # | 4 | # |
5 | # Copyright (c) 2016 Kinichiro Inoguchi <inoguchi@openbsd.org> | 5 | # Copyright (c) 2016 Kinichiro Inoguchi <inoguchi@openbsd.org> |
6 | # | 6 | # |
@@ -867,6 +867,55 @@ __EOF__ | |||
867 | diff $server_dir/testpubkey.pem $revoke_cert.pub | 867 | diff $server_dir/testpubkey.pem $revoke_cert.pub |
868 | check_exit_status $? | 868 | check_exit_status $? |
869 | 869 | ||
870 | start_message "x509 ... test -new" | ||
871 | $openssl_bin genrsa -out $server_dir/ca-new.key 2048 | ||
872 | check_exit_status $? | ||
873 | $openssl_bin x509 -new -set_issuer '/CN=test-issuer' \ | ||
874 | -set_subject '/CN=test-subject' \ | ||
875 | -out $server_dir/new.pem -days 1 -key $server_dir/ca-new.key \ | ||
876 | -force_pubkey $revoke_cert.pub | ||
877 | check_exit_status $? | ||
878 | $openssl_bin x509 -in $server_dir/new.pem -pubkey -noout \ | ||
879 | > $server_dir/new.pem.pub | ||
880 | check_exit_status $? | ||
881 | |||
882 | start_message "x509 ... check if -new cert has proper pubkey" | ||
883 | diff $server_dir/testpubkey.pem $server_dir/new.pem.pub | ||
884 | check_exit_status $? | ||
885 | |||
886 | start_message "x509 ... check if -new cert has proper issuer & subject" | ||
887 | if [ "$($openssl_bin x509 -in $server_dir/new.pem -issuer -noout)" != \ | ||
888 | "issuer= /CN=test-issuer" ]; then | ||
889 | exit 1 | ||
890 | fi | ||
891 | if [ "$($openssl_bin x509 -in $server_dir/new.pem -subject -noout)" != \ | ||
892 | "subject= /CN=test-subject" ]; then | ||
893 | exit 1 | ||
894 | fi | ||
895 | check_exit_status 0 | ||
896 | |||
897 | start_message "x509 ... test -new without -force_pubkey" | ||
898 | $openssl_bin x509 -new -set_subject '/CN=test-subject2' \ | ||
899 | -out $server_dir/new2.pem -days 1 -key $server_dir/ca-new.key | ||
900 | check_exit_status $? | ||
901 | $openssl_bin x509 -in $server_dir/new2.pem -pubkey -noout \ | ||
902 | > $server_dir/new2.pem.pub | ||
903 | check_exit_status $? | ||
904 | $openssl_bin rsa -in $server_dir/ca-new.key -pubout \ | ||
905 | -out $server_dir/ca-new.pubkey | ||
906 | check_exit_status $? | ||
907 | diff $server_dir/new2.pem.pub $server_dir/ca-new.pubkey | ||
908 | check_exit_status $? | ||
909 | if [ "$($openssl_bin x509 -in $server_dir/new2.pem -issuer -noout)" \ | ||
910 | != "issuer= /CN=test-subject2" ]; then | ||
911 | exit 1 | ||
912 | fi | ||
913 | if [ "$($openssl_bin x509 -in $server_dir/new2.pem -subject -noout)" \ | ||
914 | != "subject= /CN=test-subject2" ]; then | ||
915 | exit 1 | ||
916 | fi | ||
917 | check_exit_status 0 | ||
918 | |||
870 | start_message "ca ... issue cert for server csr#3" | 919 | start_message "ca ... issue cert for server csr#3" |
871 | 920 | ||
872 | sv_ecdsa_cert=$server_dir/sv_ecdsa_cert.pem | 921 | sv_ecdsa_cert=$server_dir/sv_ecdsa_cert.pem |
diff --git a/src/usr.bin/openssl/openssl.1 b/src/usr.bin/openssl/openssl.1 index b608b1634e..0e2ffbcd00 100644 --- a/src/usr.bin/openssl/openssl.1 +++ b/src/usr.bin/openssl/openssl.1 | |||
@@ -1,4 +1,4 @@ | |||
1 | .\" $OpenBSD: openssl.1,v 1.154 2024/01/12 11:24:03 job Exp $ | 1 | .\" $OpenBSD: openssl.1,v 1.155 2024/01/26 11:58:37 job Exp $ |
2 | .\" ==================================================================== | 2 | .\" ==================================================================== |
3 | .\" Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. | 3 | .\" Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. |
4 | .\" | 4 | .\" |
@@ -110,7 +110,7 @@ | |||
110 | .\" copied and put under another distribution licence | 110 | .\" copied and put under another distribution licence |
111 | .\" [including the GNU Public Licence.] | 111 | .\" [including the GNU Public Licence.] |
112 | .\" | 112 | .\" |
113 | .Dd $Mdocdate: January 12 2024 $ | 113 | .Dd $Mdocdate: January 26 2024 $ |
114 | .Dt OPENSSL 1 | 114 | .Dt OPENSSL 1 |
115 | .Os | 115 | .Os |
116 | .Sh NAME | 116 | .Sh NAME |
@@ -6112,6 +6112,7 @@ version. | |||
6112 | .Op Fl modulus | 6112 | .Op Fl modulus |
6113 | .Op Fl multivalue-rdn | 6113 | .Op Fl multivalue-rdn |
6114 | .Op Fl nameopt Ar option | 6114 | .Op Fl nameopt Ar option |
6115 | .Op Fl new | ||
6115 | .Op Fl next_serial | 6116 | .Op Fl next_serial |
6116 | .Op Fl noout | 6117 | .Op Fl noout |
6117 | .Op Fl ocsp_uri | 6118 | .Op Fl ocsp_uri |
@@ -6153,10 +6154,14 @@ The following are x509 input, output, and general purpose options: | |||
6153 | .It Fl in Ar file | 6154 | .It Fl in Ar file |
6154 | The input file to read from, | 6155 | The input file to read from, |
6155 | or standard input if not specified. | 6156 | or standard input if not specified. |
6157 | This option cannot be used with | ||
6158 | .Fl new . | ||
6156 | .It Fl inform Cm der | net | pem | 6159 | .It Fl inform Cm der | net | pem |
6157 | The input format. | 6160 | The input format. |
6158 | Normally, the command will expect an X.509 certificate, | 6161 | Normally, the command will expect an X.509 certificate, |
6159 | but this can change if other options such as | 6162 | but this can change if other options such as |
6163 | .Fl in | ||
6164 | or | ||
6160 | .Fl req | 6165 | .Fl req |
6161 | are present. | 6166 | are present. |
6162 | .It Fl md5 | sha1 | 6167 | .It Fl md5 | sha1 |
@@ -6710,8 +6715,22 @@ The format of the key file used in the | |||
6710 | and | 6715 | and |
6711 | .Fl signkey | 6716 | .Fl signkey |
6712 | options. | 6717 | options. |
6718 | .It Fl new | ||
6719 | Generate a new certificate using the subject given by | ||
6720 | .Fl set_subject | ||
6721 | and signed by | ||
6722 | .Fl signkey . | ||
6723 | If no public key is provided with | ||
6724 | .Fl force_pubkey , | ||
6725 | the resulting certificate is self-signed. | ||
6726 | This option cannot be used with | ||
6727 | .Fl in | ||
6728 | or | ||
6729 | .Fl req . | ||
6713 | .It Fl req | 6730 | .It Fl req |
6714 | Expect a certificate request on input instead of a certificate. | 6731 | Expect a certificate request on input instead of a certificate. |
6732 | This option cannot be used with | ||
6733 | .Fl new . | ||
6715 | .It Fl set_issuer Ar name | 6734 | .It Fl set_issuer Ar name |
6716 | The issuer name to use. | 6735 | The issuer name to use. |
6717 | .Ar name | 6736 | .Ar name |
diff --git a/src/usr.bin/openssl/x509.c b/src/usr.bin/openssl/x509.c index 332399e7cc..0d5cf5d033 100644 --- a/src/usr.bin/openssl/x509.c +++ b/src/usr.bin/openssl/x509.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x509.c,v 1.36 2024/01/12 11:24:03 job Exp $ */ | 1 | /* $OpenBSD: x509.c,v 1.37 2024/01/26 11:58:37 job Exp $ */ |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
@@ -81,7 +81,8 @@ | |||
81 | 81 | ||
82 | static int callb(int ok, X509_STORE_CTX *ctx); | 82 | static int callb(int ok, X509_STORE_CTX *ctx); |
83 | static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, | 83 | static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, |
84 | const EVP_MD *digest, CONF *conf, char *section, X509_NAME *issuer); | 84 | const EVP_MD *digest, CONF *conf, char *section, X509_NAME *issuer, |
85 | char *force_pubkey); | ||
85 | static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest, | 86 | static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest, |
86 | X509 *x, X509 *xca, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *sigopts, | 87 | X509 *x, X509 *xca, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *sigopts, |
87 | char *serial, int create, int days, int clrext, CONF *conf, char *section, | 88 | char *serial, int create, int days, int clrext, CONF *conf, char *section, |
@@ -127,6 +128,7 @@ static struct { | |||
127 | const EVP_MD *md_alg; | 128 | const EVP_MD *md_alg; |
128 | int modulus; | 129 | int modulus; |
129 | int multirdn; | 130 | int multirdn; |
131 | int new; | ||
130 | int next_serial; | 132 | int next_serial; |
131 | unsigned long nmflag; | 133 | unsigned long nmflag; |
132 | int noout; | 134 | int noout; |
@@ -531,6 +533,12 @@ static const struct option x509_options[] = { | |||
531 | }, | 533 | }, |
532 | #endif | 534 | #endif |
533 | { | 535 | { |
536 | .name = "key", | ||
537 | .argname = "file", | ||
538 | .type = OPTION_ARG_FUNC, | ||
539 | .opt.argfunc = x509_opt_signkey, | ||
540 | }, | ||
541 | { | ||
534 | .name = "keyform", | 542 | .name = "keyform", |
535 | .argname = "fmt", | 543 | .argname = "fmt", |
536 | .desc = "Private key format - default PEM", | 544 | .desc = "Private key format - default PEM", |
@@ -558,6 +566,12 @@ static const struct option x509_options[] = { | |||
558 | .opt.argfunc = x509_opt_nameopt, | 566 | .opt.argfunc = x509_opt_nameopt, |
559 | }, | 567 | }, |
560 | { | 568 | { |
569 | .name = "new", | ||
570 | .desc = "Generate a new certificate", | ||
571 | .type = OPTION_FLAG, | ||
572 | .opt.flag = &cfg.new, | ||
573 | }, | ||
574 | { | ||
561 | .name = "next_serial", | 575 | .name = "next_serial", |
562 | .desc = "Print the next serial number", | 576 | .desc = "Print the next serial number", |
563 | .type = OPTION_ORDER, | 577 | .type = OPTION_ORDER, |
@@ -758,7 +772,7 @@ x509_usage(void) | |||
758 | " [-in file] [-inform der | net | pem] [-issuer]\n" | 772 | " [-in file] [-inform der | net | pem] [-issuer]\n" |
759 | " [-issuer_hash] [-issuer_hash_old] [-keyform der | pem]\n" | 773 | " [-issuer_hash] [-issuer_hash_old] [-keyform der | pem]\n" |
760 | " [-md5 | -sha1] [-modulus] [-multivalue-rdn]\n" | 774 | " [-md5 | -sha1] [-modulus] [-multivalue-rdn]\n" |
761 | " [-nameopt option] [-next_serial] [-noout] [-ocsp_uri]\n" | 775 | " [-nameopt option] [-new] [-next_serial] [-noout] [-ocsp_uri]\n" |
762 | " [-ocspid] [-out file] [-outform der | net | pem]\n" | 776 | " [-ocspid] [-out file] [-outform der | net | pem]\n" |
763 | " [-passin arg] [-pubkey] [-purpose] [-req] [-serial]\n" | 777 | " [-passin arg] [-pubkey] [-purpose] [-req] [-serial]\n" |
764 | " [-set_issuer name] [-set_serial n] [-set_subject name]\n" | 778 | " [-set_issuer name] [-set_serial n] [-set_subject name]\n" |
@@ -778,6 +792,7 @@ x509_main(int argc, char **argv) | |||
778 | X509 *x = NULL, *xca = NULL; | 792 | X509 *x = NULL, *xca = NULL; |
779 | X509_NAME *iname = NULL, *sname = NULL; | 793 | X509_NAME *iname = NULL, *sname = NULL; |
780 | EVP_PKEY *Fpkey = NULL, *Upkey = NULL, *CApkey = NULL; | 794 | EVP_PKEY *Fpkey = NULL, *Upkey = NULL, *CApkey = NULL; |
795 | EVP_PKEY *pkey; | ||
781 | int i; | 796 | int i; |
782 | BIO *out = NULL; | 797 | BIO *out = NULL; |
783 | BIO *STDout = NULL; | 798 | BIO *STDout = NULL; |
@@ -869,8 +884,28 @@ x509_main(int argc, char **argv) | |||
869 | cfg.keyformat, 0, NULL, "Forced key")) == NULL) | 884 | cfg.keyformat, 0, NULL, "Forced key")) == NULL) |
870 | goto end; | 885 | goto end; |
871 | } | 886 | } |
887 | if (cfg.new) { | ||
888 | if (cfg.infile != NULL) { | ||
889 | BIO_printf(bio_err, "Can't combine -new and -in\n"); | ||
890 | goto end; | ||
891 | } | ||
892 | if (cfg.reqfile) { | ||
893 | BIO_printf(bio_err, "Can't combine -new and -req\n"); | ||
894 | goto end; | ||
895 | } | ||
896 | if (cfg.set_subject == NULL) { | ||
897 | BIO_printf(bio_err, "Must use -set_subject with -new\n"); | ||
898 | goto end; | ||
899 | } | ||
900 | if (cfg.keyfile == NULL) { | ||
901 | BIO_printf(bio_err, "Must use -signkey with -new\n"); | ||
902 | goto end; | ||
903 | } | ||
904 | if ((Upkey = load_key(bio_err, cfg.keyfile, cfg.keyformat, 0, | ||
905 | passin, "Private key")) == NULL) | ||
906 | goto end; | ||
907 | } | ||
872 | if (cfg.reqfile) { | 908 | if (cfg.reqfile) { |
873 | EVP_PKEY *pkey; | ||
874 | BIO *in; | 909 | BIO *in; |
875 | 910 | ||
876 | if (!cfg.sign_flag && !cfg.CA_flag) { | 911 | if (!cfg.sign_flag && !cfg.CA_flag) { |
@@ -919,6 +954,8 @@ x509_main(int argc, char **argv) | |||
919 | print_name(bio_err, "subject=", X509_REQ_get_subject_name(req), | 954 | print_name(bio_err, "subject=", X509_REQ_get_subject_name(req), |
920 | cfg.nmflag); | 955 | cfg.nmflag); |
921 | 956 | ||
957 | } | ||
958 | if (cfg.reqfile || cfg.new) { | ||
922 | if ((x = X509_new()) == NULL) | 959 | if ((x = X509_new()) == NULL) |
923 | goto end; | 960 | goto end; |
924 | 961 | ||
@@ -959,6 +996,8 @@ x509_main(int argc, char **argv) | |||
959 | if ((pkey = Fpkey) == NULL) | 996 | if ((pkey = Fpkey) == NULL) |
960 | pkey = X509_REQ_get0_pubkey(req); | 997 | pkey = X509_REQ_get0_pubkey(req); |
961 | if (pkey == NULL) | 998 | if (pkey == NULL) |
999 | pkey = Upkey; | ||
1000 | if (pkey == NULL) | ||
962 | goto end; | 1001 | goto end; |
963 | if (!X509_set_pubkey(x, pkey)) | 1002 | if (!X509_set_pubkey(x, pkey)) |
964 | goto end; | 1003 | goto end; |
@@ -1263,10 +1302,7 @@ x509_main(int argc, char **argv) | |||
1263 | BIO_printf(STDout, "%02X%c", md[j], | 1302 | BIO_printf(STDout, "%02X%c", md[j], |
1264 | (j + 1 == (int)n) ? '\n' : ':'); | 1303 | (j + 1 == (int)n) ? '\n' : ':'); |
1265 | } | 1304 | } |
1266 | |||
1267 | /* should be in the library */ | ||
1268 | } else if (cfg.sign_flag == i && cfg.x509req == 0) { | 1305 | } else if (cfg.sign_flag == i && cfg.x509req == 0) { |
1269 | BIO_printf(bio_err, "Getting Private key\n"); | ||
1270 | if (Upkey == NULL) { | 1306 | if (Upkey == NULL) { |
1271 | Upkey = load_key(bio_err, cfg.keyfile, | 1307 | Upkey = load_key(bio_err, cfg.keyfile, |
1272 | cfg.keyformat, 0, passin, | 1308 | cfg.keyformat, 0, passin, |
@@ -1276,10 +1312,10 @@ x509_main(int argc, char **argv) | |||
1276 | } | 1312 | } |
1277 | if (!sign(x, Upkey, cfg.days, | 1313 | if (!sign(x, Upkey, cfg.days, |
1278 | cfg.clrext, cfg.digest, | 1314 | cfg.clrext, cfg.digest, |
1279 | extconf, cfg.extsect, iname)) | 1315 | extconf, cfg.extsect, iname, |
1316 | cfg.force_pubkey)) | ||
1280 | goto end; | 1317 | goto end; |
1281 | } else if (cfg.CA_flag == i) { | 1318 | } else if (cfg.CA_flag == i) { |
1282 | BIO_printf(bio_err, "Getting CA Private Key\n"); | ||
1283 | if (cfg.CAkeyfile != NULL) { | 1319 | if (cfg.CAkeyfile != NULL) { |
1284 | CApkey = load_key(bio_err, cfg.CAkeyfile, | 1320 | CApkey = load_key(bio_err, cfg.CAkeyfile, |
1285 | cfg.CAkeyformat, 0, passin, | 1321 | cfg.CAkeyformat, 0, passin, |
@@ -1564,7 +1600,7 @@ callb(int ok, X509_STORE_CTX *ctx) | |||
1564 | /* self sign */ | 1600 | /* self sign */ |
1565 | static int | 1601 | static int |
1566 | sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, const EVP_MD *digest, | 1602 | sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, const EVP_MD *digest, |
1567 | CONF *conf, char *section, X509_NAME *issuer) | 1603 | CONF *conf, char *section, X509_NAME *issuer, char *force_pubkey) |
1568 | { | 1604 | { |
1569 | EVP_PKEY *pktmp; | 1605 | EVP_PKEY *pktmp; |
1570 | 1606 | ||
@@ -1591,8 +1627,10 @@ sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, const EVP_MD *digest, | |||
1591 | (long) 60 * 60 * 24 * days) == NULL) | 1627 | (long) 60 * 60 * 24 * days) == NULL) |
1592 | goto err; | 1628 | goto err; |
1593 | 1629 | ||
1594 | if (!X509_set_pubkey(x, pkey)) | 1630 | if (force_pubkey == NULL) { |
1595 | goto err; | 1631 | if (!X509_set_pubkey(x, pkey)) |
1632 | goto err; | ||
1633 | } | ||
1596 | if (clrext) { | 1634 | if (clrext) { |
1597 | while (X509_get_ext_count(x) > 0) { | 1635 | while (X509_get_ext_count(x) > 0) { |
1598 | if (X509_delete_ext(x, 0) == NULL) | 1636 | if (X509_delete_ext(x, 0) == NULL) |