xref: /freebsd/crypto/openssl/apps/spkac.c (revision b077aed33b7b6aefca7b17ddb250cf521f938613)
16f9291ceSJung-uk Kim /*
2*b077aed3SPierre Pronchery  * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved.
3e71b7053SJung-uk Kim  *
4*b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5e71b7053SJung-uk Kim  * this file except in compliance with the License.  You can obtain a copy
6e71b7053SJung-uk Kim  * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim  * https://www.openssl.org/source/license.html
8f579bf8eSKris Kennaway  */
9e71b7053SJung-uk Kim 
10f579bf8eSKris Kennaway #include <stdio.h>
11f579bf8eSKris Kennaway #include <stdlib.h>
12f579bf8eSKris Kennaway #include <string.h>
13f579bf8eSKris Kennaway #include <time.h>
14f579bf8eSKris Kennaway #include "apps.h"
15e71b7053SJung-uk Kim #include "progs.h"
16f579bf8eSKris Kennaway #include <openssl/bio.h>
17f579bf8eSKris Kennaway #include <openssl/conf.h>
18f579bf8eSKris Kennaway #include <openssl/err.h>
19f579bf8eSKris Kennaway #include <openssl/evp.h>
20f579bf8eSKris Kennaway #include <openssl/x509.h>
21f579bf8eSKris Kennaway #include <openssl/pem.h>
22f579bf8eSKris Kennaway 
23e71b7053SJung-uk Kim typedef enum OPTION_choice {
24*b077aed3SPierre Pronchery     OPT_COMMON,
25e71b7053SJung-uk Kim     OPT_NOOUT, OPT_PUBKEY, OPT_VERIFY, OPT_IN, OPT_OUT,
26e71b7053SJung-uk Kim     OPT_ENGINE, OPT_KEY, OPT_CHALLENGE, OPT_PASSIN, OPT_SPKAC,
27*b077aed3SPierre Pronchery     OPT_SPKSECT, OPT_KEYFORM, OPT_DIGEST,
28*b077aed3SPierre Pronchery     OPT_PROV_ENUM
29e71b7053SJung-uk Kim } OPTION_CHOICE;
30f579bf8eSKris Kennaway 
31e71b7053SJung-uk Kim const OPTIONS spkac_options[] = {
32*b077aed3SPierre Pronchery     OPT_SECTION("General"),
33e71b7053SJung-uk Kim     {"help", OPT_HELP, '-', "Display this summary"},
34e71b7053SJung-uk Kim     {"spksect", OPT_SPKSECT, 's',
35e71b7053SJung-uk Kim      "Specify the name of an SPKAC-dedicated section of configuration"},
36e71b7053SJung-uk Kim #ifndef OPENSSL_NO_ENGINE
37e71b7053SJung-uk Kim     {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
38e71b7053SJung-uk Kim #endif
39*b077aed3SPierre Pronchery 
40*b077aed3SPierre Pronchery     OPT_SECTION("Input"),
41*b077aed3SPierre Pronchery     {"in", OPT_IN, '<', "Input file"},
42*b077aed3SPierre Pronchery     {"key", OPT_KEY, '<', "Create SPKAC using private key"},
43*b077aed3SPierre Pronchery     {"keyform", OPT_KEYFORM, 'f', "Private key file format (ENGINE, other values ignored)"},
44*b077aed3SPierre Pronchery     {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
45*b077aed3SPierre Pronchery     {"challenge", OPT_CHALLENGE, 's', "Challenge string"},
46*b077aed3SPierre Pronchery     {"spkac", OPT_SPKAC, 's', "Alternative SPKAC name"},
47*b077aed3SPierre Pronchery 
48*b077aed3SPierre Pronchery     OPT_SECTION("Output"),
49*b077aed3SPierre Pronchery     {"digest", OPT_DIGEST, 's', "Sign new SPKAC with the specified digest (default: MD5)" },
50*b077aed3SPierre Pronchery     {"out", OPT_OUT, '>', "Output file"},
51*b077aed3SPierre Pronchery     {"noout", OPT_NOOUT, '-', "Don't print SPKAC"},
52*b077aed3SPierre Pronchery     {"pubkey", OPT_PUBKEY, '-', "Output public key"},
53*b077aed3SPierre Pronchery     {"verify", OPT_VERIFY, '-', "Verify SPKAC signature"},
54*b077aed3SPierre Pronchery 
55*b077aed3SPierre Pronchery     OPT_PROV_OPTIONS,
56e71b7053SJung-uk Kim     {NULL}
57e71b7053SJung-uk Kim };
58f579bf8eSKris Kennaway 
spkac_main(int argc,char ** argv)59e71b7053SJung-uk Kim int spkac_main(int argc, char **argv)
60f579bf8eSKris Kennaway {
61e71b7053SJung-uk Kim     BIO *out = NULL;
625c87c606SMark Murray     CONF *conf = NULL;
63e71b7053SJung-uk Kim     ENGINE *e = NULL;
64f579bf8eSKris Kennaway     EVP_PKEY *pkey = NULL;
65e71b7053SJung-uk Kim     NETSCAPE_SPKI *spki = NULL;
66e71b7053SJung-uk Kim     char *challenge = NULL, *keyfile = NULL;
67e71b7053SJung-uk Kim     char *infile = NULL, *outfile = NULL, *passinarg = NULL, *passin = NULL;
68e71b7053SJung-uk Kim     char *spkstr = NULL, *prog;
69e71b7053SJung-uk Kim     const char *spkac = "SPKAC", *spksect = "default";
70*b077aed3SPierre Pronchery     const char *digest = "MD5";
71*b077aed3SPierre Pronchery     EVP_MD *md = NULL;
72e71b7053SJung-uk Kim     int i, ret = 1, verify = 0, noout = 0, pubkey = 0;
73*b077aed3SPierre Pronchery     int keyformat = FORMAT_UNDEF;
74e71b7053SJung-uk Kim     OPTION_CHOICE o;
75f579bf8eSKris Kennaway 
76e71b7053SJung-uk Kim     prog = opt_init(argc, argv, spkac_options);
77e71b7053SJung-uk Kim     while ((o = opt_next()) != OPT_EOF) {
78e71b7053SJung-uk Kim         switch (o) {
79e71b7053SJung-uk Kim         case OPT_EOF:
80e71b7053SJung-uk Kim         case OPT_ERR:
81e71b7053SJung-uk Kim  opthelp:
82e71b7053SJung-uk Kim             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
835c87c606SMark Murray             goto end;
84e71b7053SJung-uk Kim         case OPT_HELP:
85e71b7053SJung-uk Kim             opt_help(spkac_options);
86e71b7053SJung-uk Kim             ret = 0;
87e71b7053SJung-uk Kim             goto end;
88e71b7053SJung-uk Kim         case OPT_IN:
89e71b7053SJung-uk Kim             infile = opt_arg();
90e71b7053SJung-uk Kim             break;
91e71b7053SJung-uk Kim         case OPT_OUT:
92e71b7053SJung-uk Kim             outfile = opt_arg();
93e71b7053SJung-uk Kim             break;
94e71b7053SJung-uk Kim         case OPT_NOOUT:
95f579bf8eSKris Kennaway             noout = 1;
96e71b7053SJung-uk Kim             break;
97e71b7053SJung-uk Kim         case OPT_PUBKEY:
98f579bf8eSKris Kennaway             pubkey = 1;
99e71b7053SJung-uk Kim             break;
100e71b7053SJung-uk Kim         case OPT_VERIFY:
101f579bf8eSKris Kennaway             verify = 1;
102e71b7053SJung-uk Kim             break;
103e71b7053SJung-uk Kim         case OPT_PASSIN:
104e71b7053SJung-uk Kim             passinarg = opt_arg();
105e71b7053SJung-uk Kim             break;
106e71b7053SJung-uk Kim         case OPT_KEY:
107e71b7053SJung-uk Kim             keyfile = opt_arg();
108e71b7053SJung-uk Kim             break;
109e71b7053SJung-uk Kim         case OPT_KEYFORM:
110e71b7053SJung-uk Kim             if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyformat))
111e71b7053SJung-uk Kim                 goto opthelp;
112e71b7053SJung-uk Kim             break;
113e71b7053SJung-uk Kim         case OPT_CHALLENGE:
114e71b7053SJung-uk Kim             challenge = opt_arg();
115e71b7053SJung-uk Kim             break;
116e71b7053SJung-uk Kim         case OPT_SPKAC:
117e71b7053SJung-uk Kim             spkac = opt_arg();
118e71b7053SJung-uk Kim             break;
119e71b7053SJung-uk Kim         case OPT_SPKSECT:
120e71b7053SJung-uk Kim             spksect = opt_arg();
121e71b7053SJung-uk Kim             break;
122*b077aed3SPierre Pronchery         case OPT_DIGEST:
123*b077aed3SPierre Pronchery             digest = opt_arg();
124*b077aed3SPierre Pronchery             break;
125e71b7053SJung-uk Kim         case OPT_ENGINE:
126e71b7053SJung-uk Kim             e = setup_engine(opt_arg(), 0);
127e71b7053SJung-uk Kim             break;
128*b077aed3SPierre Pronchery         case OPT_PROV_CASES:
129*b077aed3SPierre Pronchery             if (!opt_provider(o))
130*b077aed3SPierre Pronchery                 goto end;
131*b077aed3SPierre Pronchery             break;
132f579bf8eSKris Kennaway         }
133f579bf8eSKris Kennaway     }
134*b077aed3SPierre Pronchery 
135*b077aed3SPierre Pronchery     /* No extra arguments. */
136e71b7053SJung-uk Kim     argc = opt_num_rest();
137e71b7053SJung-uk Kim     if (argc != 0)
138e71b7053SJung-uk Kim         goto opthelp;
139f579bf8eSKris Kennaway 
140e71b7053SJung-uk Kim     if (!app_passwd(passinarg, NULL, &passin, NULL)) {
141f579bf8eSKris Kennaway         BIO_printf(bio_err, "Error getting password\n");
142f579bf8eSKris Kennaway         goto end;
143f579bf8eSKris Kennaway     }
1445c87c606SMark Murray 
14547902a71SJung-uk Kim     if (keyfile != NULL) {
146*b077aed3SPierre Pronchery         if (!opt_md(digest, &md))
147*b077aed3SPierre Pronchery             goto end;
148*b077aed3SPierre Pronchery 
149e71b7053SJung-uk Kim         pkey = load_key(strcmp(keyfile, "-") ? keyfile : NULL,
150e71b7053SJung-uk Kim                         keyformat, 1, passin, e, "private key");
15147902a71SJung-uk Kim         if (pkey == NULL)
152f579bf8eSKris Kennaway             goto end;
153f579bf8eSKris Kennaway         spki = NETSCAPE_SPKI_new();
15447902a71SJung-uk Kim         if (spki == NULL)
15547902a71SJung-uk Kim             goto end;
15647902a71SJung-uk Kim         if (challenge != NULL)
1576f9291ceSJung-uk Kim             ASN1_STRING_set(spki->spkac->challenge,
1583b4e3dcbSSimon L. B. Nielsen                             challenge, (int)strlen(challenge));
159*b077aed3SPierre Pronchery         if (!NETSCAPE_SPKI_set_pubkey(spki, pkey)) {
160*b077aed3SPierre Pronchery             BIO_printf(bio_err, "Error setting public key\n");
161*b077aed3SPierre Pronchery             goto end;
162*b077aed3SPierre Pronchery         }
163*b077aed3SPierre Pronchery         i = NETSCAPE_SPKI_sign(spki, pkey, md);
164*b077aed3SPierre Pronchery         if (i <= 0) {
165*b077aed3SPierre Pronchery             BIO_printf(bio_err, "Error signing SPKAC\n");
166*b077aed3SPierre Pronchery             goto end;
167*b077aed3SPierre Pronchery         }
168f579bf8eSKris Kennaway         spkstr = NETSCAPE_SPKI_b64_encode(spki);
16947902a71SJung-uk Kim         if (spkstr == NULL)
17047902a71SJung-uk Kim             goto end;
171f579bf8eSKris Kennaway 
172e71b7053SJung-uk Kim         out = bio_open_default(outfile, 'w', FORMAT_TEXT);
173e71b7053SJung-uk Kim         if (out == NULL) {
174e71b7053SJung-uk Kim             OPENSSL_free(spkstr);
175f579bf8eSKris Kennaway             goto end;
176f579bf8eSKris Kennaway         }
177f579bf8eSKris Kennaway         BIO_printf(out, "SPKAC=%s\n", spkstr);
178ddd58736SKris Kennaway         OPENSSL_free(spkstr);
179f579bf8eSKris Kennaway         ret = 0;
180f579bf8eSKris Kennaway         goto end;
181f579bf8eSKris Kennaway     }
182f579bf8eSKris Kennaway 
183e71b7053SJung-uk Kim     if ((conf = app_load_config(infile)) == NULL)
184f579bf8eSKris Kennaway         goto end;
185f579bf8eSKris Kennaway 
1865c87c606SMark Murray     spkstr = NCONF_get_string(conf, spksect, spkac);
187f579bf8eSKris Kennaway 
188e71b7053SJung-uk Kim     if (spkstr == NULL) {
189f579bf8eSKris Kennaway         BIO_printf(bio_err, "Can't find SPKAC called \"%s\"\n", spkac);
190f579bf8eSKris Kennaway         ERR_print_errors(bio_err);
191f579bf8eSKris Kennaway         goto end;
192f579bf8eSKris Kennaway     }
193f579bf8eSKris Kennaway 
194f579bf8eSKris Kennaway     spki = NETSCAPE_SPKI_b64_decode(spkstr, -1);
195f579bf8eSKris Kennaway 
19647902a71SJung-uk Kim     if (spki == NULL) {
197f579bf8eSKris Kennaway         BIO_printf(bio_err, "Error loading SPKAC\n");
198f579bf8eSKris Kennaway         ERR_print_errors(bio_err);
199f579bf8eSKris Kennaway         goto end;
200f579bf8eSKris Kennaway     }
201f579bf8eSKris Kennaway 
202e71b7053SJung-uk Kim     out = bio_open_default(outfile, 'w', FORMAT_TEXT);
203e71b7053SJung-uk Kim     if (out == NULL)
204f579bf8eSKris Kennaway         goto end;
205f579bf8eSKris Kennaway 
2066f9291ceSJung-uk Kim     if (!noout)
2076f9291ceSJung-uk Kim         NETSCAPE_SPKI_print(out, spki);
208f579bf8eSKris Kennaway     pkey = NETSCAPE_SPKI_get_pubkey(spki);
209f579bf8eSKris Kennaway     if (verify) {
210f579bf8eSKris Kennaway         i = NETSCAPE_SPKI_verify(spki, pkey);
21147902a71SJung-uk Kim         if (i > 0) {
2126f9291ceSJung-uk Kim             BIO_printf(bio_err, "Signature OK\n");
21347902a71SJung-uk Kim         } else {
214f579bf8eSKris Kennaway             BIO_printf(bio_err, "Signature Failure\n");
215f579bf8eSKris Kennaway             ERR_print_errors(bio_err);
216f579bf8eSKris Kennaway             goto end;
217f579bf8eSKris Kennaway         }
218f579bf8eSKris Kennaway     }
2196f9291ceSJung-uk Kim     if (pubkey)
2206f9291ceSJung-uk Kim         PEM_write_bio_PUBKEY(out, pkey);
221f579bf8eSKris Kennaway 
222f579bf8eSKris Kennaway     ret = 0;
223f579bf8eSKris Kennaway 
224f579bf8eSKris Kennaway  end:
225*b077aed3SPierre Pronchery     EVP_MD_free(md);
2265c87c606SMark Murray     NCONF_free(conf);
227f579bf8eSKris Kennaway     NETSCAPE_SPKI_free(spki);
228ddd58736SKris Kennaway     BIO_free_all(out);
229f579bf8eSKris Kennaway     EVP_PKEY_free(pkey);
2306cf8931aSJung-uk Kim     release_engine(e);
2316f9291ceSJung-uk Kim     OPENSSL_free(passin);
232e71b7053SJung-uk Kim     return ret;
233f579bf8eSKris Kennaway }
234