genpkey.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /* apps/genpkey.c */
  2. /*
  3. * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
  4. * 2006
  5. */
  6. /* ====================================================================
  7. * Copyright (c) 2006 The OpenSSL Project. All rights reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. *
  13. * 1. Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. *
  16. * 2. Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in
  18. * the documentation and/or other materials provided with the
  19. * distribution.
  20. *
  21. * 3. All advertising materials mentioning features or use of this
  22. * software must display the following acknowledgment:
  23. * "This product includes software developed by the OpenSSL Project
  24. * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
  25. *
  26. * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
  27. * endorse or promote products derived from this software without
  28. * prior written permission. For written permission, please contact
  29. * licensing@OpenSSL.org.
  30. *
  31. * 5. Products derived from this software may not be called "OpenSSL"
  32. * nor may "OpenSSL" appear in their names without prior written
  33. * permission of the OpenSSL Project.
  34. *
  35. * 6. Redistributions of any form whatsoever must retain the following
  36. * acknowledgment:
  37. * "This product includes software developed by the OpenSSL Project
  38. * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
  39. *
  40. * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
  41. * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  42. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  43. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
  44. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  45. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  46. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  47. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  48. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  49. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  50. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  51. * OF THE POSSIBILITY OF SUCH DAMAGE.
  52. * ====================================================================
  53. *
  54. * This product includes cryptographic software written by Eric Young
  55. * (eay@cryptsoft.com). This product includes software written by Tim
  56. * Hudson (tjh@cryptsoft.com).
  57. *
  58. */
  59. #include <stdio.h>
  60. #include <string.h>
  61. #include "apps.h"
  62. #include <openssl/pem.h>
  63. #include <openssl/err.h>
  64. #include <openssl/evp.h>
  65. #ifndef OPENSSL_NO_ENGINE
  66. # include <openssl/engine.h>
  67. #endif
  68. static int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx,
  69. const char *file, ENGINE *e);
  70. static int genpkey_cb(EVP_PKEY_CTX *ctx);
  71. #define PROG genpkey_main
  72. int MAIN(int, char **);
  73. int MAIN(int argc, char **argv)
  74. {
  75. ENGINE *e = NULL;
  76. char **args, *outfile = NULL;
  77. char *passarg = NULL;
  78. BIO *in = NULL, *out = NULL;
  79. const EVP_CIPHER *cipher = NULL;
  80. int outformat;
  81. int text = 0;
  82. EVP_PKEY *pkey = NULL;
  83. EVP_PKEY_CTX *ctx = NULL;
  84. char *pass = NULL;
  85. int badarg = 0;
  86. int ret = 1, rv;
  87. int do_param = 0;
  88. if (bio_err == NULL)
  89. bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
  90. if (!load_config(bio_err, NULL))
  91. goto end;
  92. outformat = FORMAT_PEM;
  93. ERR_load_crypto_strings();
  94. OpenSSL_add_all_algorithms();
  95. args = argv + 1;
  96. while (!badarg && *args && *args[0] == '-') {
  97. if (!strcmp(*args, "-outform")) {
  98. if (args[1]) {
  99. args++;
  100. outformat = str2fmt(*args);
  101. } else
  102. badarg = 1;
  103. } else if (!strcmp(*args, "-pass")) {
  104. if (!args[1])
  105. goto bad;
  106. passarg = *(++args);
  107. }
  108. #ifndef OPENSSL_NO_ENGINE
  109. else if (strcmp(*args, "-engine") == 0) {
  110. if (!args[1])
  111. goto bad;
  112. e = setup_engine(bio_err, *(++args), 0);
  113. }
  114. #endif
  115. else if (!strcmp(*args, "-paramfile")) {
  116. if (!args[1])
  117. goto bad;
  118. args++;
  119. if (do_param == 1)
  120. goto bad;
  121. if (!init_keygen_file(bio_err, &ctx, *args, e))
  122. goto end;
  123. } else if (!strcmp(*args, "-out")) {
  124. if (args[1]) {
  125. args++;
  126. outfile = *args;
  127. } else
  128. badarg = 1;
  129. } else if (strcmp(*args, "-algorithm") == 0) {
  130. if (!args[1])
  131. goto bad;
  132. if (!init_gen_str(bio_err, &ctx, *(++args), e, do_param))
  133. goto end;
  134. } else if (strcmp(*args, "-pkeyopt") == 0) {
  135. if (!args[1])
  136. goto bad;
  137. if (!ctx) {
  138. BIO_puts(bio_err, "No keytype specified\n");
  139. goto bad;
  140. } else if (pkey_ctrl_string(ctx, *(++args)) <= 0) {
  141. BIO_puts(bio_err, "parameter setting error\n");
  142. ERR_print_errors(bio_err);
  143. goto end;
  144. }
  145. } else if (strcmp(*args, "-genparam") == 0) {
  146. if (ctx)
  147. goto bad;
  148. do_param = 1;
  149. } else if (strcmp(*args, "-text") == 0)
  150. text = 1;
  151. else {
  152. cipher = EVP_get_cipherbyname(*args + 1);
  153. if (!cipher) {
  154. BIO_printf(bio_err, "Unknown cipher %s\n", *args + 1);
  155. badarg = 1;
  156. }
  157. if (do_param == 1)
  158. badarg = 1;
  159. }
  160. args++;
  161. }
  162. if (!ctx)
  163. badarg = 1;
  164. if (badarg) {
  165. bad:
  166. BIO_printf(bio_err, "Usage: genpkey [options]\n");
  167. BIO_printf(bio_err, "where options may be\n");
  168. BIO_printf(bio_err, "-out file output file\n");
  169. BIO_printf(bio_err,
  170. "-outform X output format (DER or PEM)\n");
  171. BIO_printf(bio_err,
  172. "-pass arg output file pass phrase source\n");
  173. BIO_printf(bio_err,
  174. "-<cipher> use cipher <cipher> to encrypt the key\n");
  175. #ifndef OPENSSL_NO_ENGINE
  176. BIO_printf(bio_err,
  177. "-engine e use engine e, possibly a hardware device.\n");
  178. #endif
  179. BIO_printf(bio_err, "-paramfile file parameters file\n");
  180. BIO_printf(bio_err, "-algorithm alg the public key algorithm\n");
  181. BIO_printf(bio_err,
  182. "-pkeyopt opt:value set the public key algorithm option <opt>\n"
  183. " to value <value>\n");
  184. BIO_printf(bio_err,
  185. "-genparam generate parameters, not key\n");
  186. BIO_printf(bio_err, "-text print the in text\n");
  187. BIO_printf(bio_err,
  188. "NB: options order may be important! See the manual page.\n");
  189. goto end;
  190. }
  191. if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) {
  192. BIO_puts(bio_err, "Error getting password\n");
  193. goto end;
  194. }
  195. if (outfile) {
  196. if (!(out = BIO_new_file(outfile, "wb"))) {
  197. BIO_printf(bio_err, "Can't open output file %s\n", outfile);
  198. goto end;
  199. }
  200. } else {
  201. out = BIO_new_fp(stdout, BIO_NOCLOSE);
  202. #ifdef OPENSSL_SYS_VMS
  203. {
  204. BIO *tmpbio = BIO_new(BIO_f_linebuffer());
  205. out = BIO_push(tmpbio, out);
  206. }
  207. #endif
  208. }
  209. EVP_PKEY_CTX_set_cb(ctx, genpkey_cb);
  210. EVP_PKEY_CTX_set_app_data(ctx, bio_err);
  211. if (do_param) {
  212. if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) {
  213. BIO_puts(bio_err, "Error generating parameters\n");
  214. ERR_print_errors(bio_err);
  215. goto end;
  216. }
  217. } else {
  218. if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
  219. BIO_puts(bio_err, "Error generating key\n");
  220. ERR_print_errors(bio_err);
  221. goto end;
  222. }
  223. }
  224. if (do_param)
  225. rv = PEM_write_bio_Parameters(out, pkey);
  226. else if (outformat == FORMAT_PEM)
  227. rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass);
  228. else if (outformat == FORMAT_ASN1)
  229. rv = i2d_PrivateKey_bio(out, pkey);
  230. else {
  231. BIO_printf(bio_err, "Bad format specified for key\n");
  232. goto end;
  233. }
  234. if (rv <= 0) {
  235. BIO_puts(bio_err, "Error writing key\n");
  236. ERR_print_errors(bio_err);
  237. }
  238. if (text) {
  239. if (do_param)
  240. rv = EVP_PKEY_print_params(out, pkey, 0, NULL);
  241. else
  242. rv = EVP_PKEY_print_private(out, pkey, 0, NULL);
  243. if (rv <= 0) {
  244. BIO_puts(bio_err, "Error printing key\n");
  245. ERR_print_errors(bio_err);
  246. }
  247. }
  248. ret = 0;
  249. end:
  250. if (pkey)
  251. EVP_PKEY_free(pkey);
  252. if (ctx)
  253. EVP_PKEY_CTX_free(ctx);
  254. if (out)
  255. BIO_free_all(out);
  256. BIO_free(in);
  257. release_engine(e);
  258. if (pass)
  259. OPENSSL_free(pass);
  260. return ret;
  261. }
  262. static int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx,
  263. const char *file, ENGINE *e)
  264. {
  265. BIO *pbio;
  266. EVP_PKEY *pkey = NULL;
  267. EVP_PKEY_CTX *ctx = NULL;
  268. if (*pctx) {
  269. BIO_puts(err, "Parameters already set!\n");
  270. return 0;
  271. }
  272. pbio = BIO_new_file(file, "r");
  273. if (!pbio) {
  274. BIO_printf(err, "Can't open parameter file %s\n", file);
  275. return 0;
  276. }
  277. pkey = PEM_read_bio_Parameters(pbio, NULL);
  278. BIO_free(pbio);
  279. if (!pkey) {
  280. BIO_printf(bio_err, "Error reading parameter file %s\n", file);
  281. return 0;
  282. }
  283. ctx = EVP_PKEY_CTX_new(pkey, e);
  284. if (!ctx)
  285. goto err;
  286. if (EVP_PKEY_keygen_init(ctx) <= 0)
  287. goto err;
  288. EVP_PKEY_free(pkey);
  289. *pctx = ctx;
  290. return 1;
  291. err:
  292. BIO_puts(err, "Error initializing context\n");
  293. ERR_print_errors(err);
  294. if (ctx)
  295. EVP_PKEY_CTX_free(ctx);
  296. if (pkey)
  297. EVP_PKEY_free(pkey);
  298. return 0;
  299. }
  300. int init_gen_str(BIO *err, EVP_PKEY_CTX **pctx,
  301. const char *algname, ENGINE *e, int do_param)
  302. {
  303. EVP_PKEY_CTX *ctx = NULL;
  304. const EVP_PKEY_ASN1_METHOD *ameth;
  305. ENGINE *tmpeng = NULL;
  306. int pkey_id;
  307. if (*pctx) {
  308. BIO_puts(err, "Algorithm already set!\n");
  309. return 0;
  310. }
  311. ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1);
  312. #ifndef OPENSSL_NO_ENGINE
  313. if (!ameth && e)
  314. ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1);
  315. #endif
  316. if (!ameth) {
  317. BIO_printf(bio_err, "Algorithm %s not found\n", algname);
  318. return 0;
  319. }
  320. ERR_clear_error();
  321. EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
  322. #ifndef OPENSSL_NO_ENGINE
  323. if (tmpeng)
  324. ENGINE_finish(tmpeng);
  325. #endif
  326. ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
  327. if (!ctx)
  328. goto err;
  329. if (do_param) {
  330. if (EVP_PKEY_paramgen_init(ctx) <= 0)
  331. goto err;
  332. } else {
  333. if (EVP_PKEY_keygen_init(ctx) <= 0)
  334. goto err;
  335. }
  336. *pctx = ctx;
  337. return 1;
  338. err:
  339. BIO_printf(err, "Error initializing %s context\n", algname);
  340. ERR_print_errors(err);
  341. if (ctx)
  342. EVP_PKEY_CTX_free(ctx);
  343. return 0;
  344. }
  345. static int genpkey_cb(EVP_PKEY_CTX *ctx)
  346. {
  347. char c = '*';
  348. BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
  349. int p;
  350. p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
  351. if (p == 0)
  352. c = '.';
  353. if (p == 1)
  354. c = '+';
  355. if (p == 2)
  356. c = '*';
  357. if (p == 3)
  358. c = '\n';
  359. BIO_write(b, &c, 1);
  360. (void)BIO_flush(b);
  361. #ifdef LINT
  362. p = n;
  363. #endif
  364. return 1;
  365. }