Initial keygen support.
authorDr. Stephen Henson <steve@openssl.org>
Tue, 11 Apr 2006 13:28:52 +0000 (13:28 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Tue, 11 Apr 2006 13:28:52 +0000 (13:28 +0000)
13 files changed:
CHANGES
apps/Makefile
apps/genpkey.c [new file with mode: 0644]
apps/pkeyutl.c
apps/progs.h
crypto/asn1/ameth_lib.c
crypto/evp/Makefile
crypto/evp/evp.h
crypto/evp/evp_err.c
crypto/evp/evp_locl.h
crypto/evp/pmeth_gn.c [new file with mode: 0644]
crypto/evp/pmeth_lib.c
crypto/rsa/rsa_pmeth.c

diff --git a/CHANGES b/CHANGES
index eb7786b..472b83a 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,12 @@
 
  Changes between 0.9.8a and 0.9.9  [xx XXX xxxx]
 
+  *) New utility "genpkey" this is analagous to "genrsa" etc except it can
+     generate keys for any algorithm. Extend and update EVP_PKEY_METHOD to
+     support key and parameter generation and add initial key generation
+     functionality for RSA.
+     [Steve Henson]
+
   *) Add functions for main EVP_PKEY_method operations. The undocumented
      functions EVP_PKEY_{encrypt,decrypt} have been renamed to
      EVP_PKEY_{encrypt,decrypt}_old. 
@@ -27,7 +33,7 @@
      [Steve Henson]
 
   *) New utilities pkey and pkeyparam. These are similar to algorithm specific
-     utilities such as rsa, dsa, dsaparam etc except they processes any key
+     utilities such as rsa, dsa, dsaparam etc except they process any key
      type.
      [Steve Henson]
 
index 79f8e57..eca57d2 100644 (file)
@@ -37,7 +37,7 @@ EXE= $(PROGRAM)$(EXE_EXT)
 
 E_EXE= verify asn1pars req dgst dh dhparam enc passwd gendh errstr \
        ca crl rsa rsautl dsa dsaparam ec ecparam \
-       x509 genrsa gendsa s_server s_client speed \
+       x509 genrsa gendsa genpkey s_server s_client speed \
        s_time version pkcs7 crl2pkcs7 sess_id ciphers nseq pkcs12 \
        pkcs8 pkey pkeyparam pkeyutl spkac smime rand engine ocsp prime ts
 
@@ -53,7 +53,7 @@ RAND_SRC=app_rand.c
 E_OBJ= verify.o asn1pars.o req.o dgst.o dh.o dhparam.o enc.o passwd.o gendh.o errstr.o \
        ca.o pkcs7.o crl2p7.o crl.o \
        rsa.o rsautl.o dsa.o dsaparam.o ec.o ecparam.o \
-       x509.o genrsa.o gendsa.o s_server.o s_client.o speed.o \
+       x509.o genrsa.o gendsa.o genpkey.o s_server.o s_client.o speed.o \
        s_time.o $(A_OBJ) $(S_OBJ) $(RAND_OBJ) version.o sess_id.o \
        ciphers.o nseq.o pkcs12.o pkcs8.o pkey.o pkeyparam.o pkeyutl.o \
        spkac.o smime.o rand.o engine.o ocsp.o prime.o ts.o
@@ -61,7 +61,7 @@ E_OBJ=        verify.o asn1pars.o req.o dgst.o dh.o dhparam.o enc.o passwd.o gendh.o er
 E_SRC= verify.c asn1pars.c req.c dgst.c dh.c enc.c passwd.c gendh.c errstr.c ca.c \
        pkcs7.c crl2p7.c crl.c \
        rsa.c rsautl.c dsa.c dsaparam.c ec.c ecparam.c \
-       x509.c genrsa.c gendsa.c s_server.c s_client.c speed.c \
+       x509.c genrsa.c gendsa.c genpkey.c s_server.c s_client.c speed.c \
        s_time.c $(A_SRC) $(S_SRC) $(RAND_SRC) version.c sess_id.c \
        ciphers.c nseq.c pkcs12.c pkcs8.c pkey.c pkeyparam.c pkeyutl.c \
        spkac.c smime.c rand.c engine.c ocsp.c prime.c ts.c
diff --git a/apps/genpkey.c b/apps/genpkey.c
new file mode 100644 (file)
index 0000000..b0c06f0
--- /dev/null
@@ -0,0 +1,375 @@
+/* apps/genpkey.c */
+/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
+ * project 2006
+ */
+/* ====================================================================
+ * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include "apps.h"
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+
+static int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx,
+                               const char *file, ENGINE *e);
+static int init_gen_str(BIO *err, EVP_PKEY_CTX **pctx,
+                               const char *algname, ENGINE *e, int do_param);
+static int genpkey_cb(EVP_PKEY_CTX *ctx);
+
+#define PROG genpkey_main
+
+int MAIN(int, char **);
+
+int MAIN(int argc, char **argv)
+       {
+       ENGINE *e = NULL;
+       char **args, *outfile = NULL;
+       char *passarg = NULL;
+       BIO *in = NULL, *out = NULL;
+       const EVP_CIPHER *cipher = NULL;
+       int outformat;
+       int text = 0;
+       EVP_PKEY *pkey=NULL;
+       EVP_PKEY_CTX *ctx = NULL;
+       char *pass = NULL;
+       int badarg = 0;
+       int ret = 1;
+
+       if (bio_err == NULL)
+               bio_err = BIO_new_fp (stderr, BIO_NOCLOSE);
+
+       if (!load_config(bio_err, NULL))
+               goto end;
+
+       outformat=FORMAT_PEM;
+
+       ERR_load_crypto_strings();
+       OpenSSL_add_all_algorithms();
+       args = argv + 1;
+       while (!badarg && *args && *args[0] == '-')
+               {
+               if (!strcmp(*args,"-outform"))
+                       {
+                       if (args[1])
+                               {
+                               args++;
+                               outformat=str2fmt(*args);
+                               }
+                       else badarg = 1;
+                       }
+               else if (!strcmp(*args,"-pass"))
+                       {
+                       if (!args[1]) goto bad;
+                       passarg= *(++args);
+                       }
+#ifndef OPENSSL_NO_ENGINE
+               else if (strcmp(*args,"-engine") == 0)
+                       {
+                       if (!args[1])
+                               goto bad;
+                       e = setup_engine(bio_err, *(++args), 0);
+                       }
+#endif
+               else if (!strcmp (*args, "-paramfile"))
+                       {
+                       if (!args[1])
+                               goto bad;
+                       args++;
+                       if (!init_keygen_file(bio_err, &ctx, *args, e))
+                               goto end;
+                       }
+               else if (!strcmp (*args, "-out"))
+                       {
+                       if (args[1])
+                               {
+                               args++;
+                               outfile = *args;
+                               }
+                       else badarg = 1;
+                       }
+               else if (strcmp(*args,"-algorithm") == 0)
+                       {
+                       if (!args[1])
+                               goto bad;
+                       if (!init_gen_str(bio_err, &ctx, *(++args), e, 0))
+                               goto end;
+                       }
+               else if (strcmp(*args,"-param") == 0)
+                       {
+                       if (!args[1])
+                               goto bad;
+                       if (!ctx)
+                               {
+                               BIO_puts(bio_err, "No keytype specified\n");
+                               goto bad;
+                               }
+                       else if (pkey_ctrl_string(ctx, *(++args)) <= 0)
+                               {
+                               BIO_puts(bio_err, "parameter setting error\n");
+                               ERR_print_errors(bio_err);
+                               goto end;
+                               }
+                       }
+               else if (strcmp(*args,"-text") == 0)
+                       text=1;
+               else
+                       {
+                       cipher = EVP_get_cipherbyname(*args + 1);
+                       if (!cipher)
+                               {
+                               BIO_printf(bio_err, "Unknown cipher %s\n",
+                                                               *args + 1);
+                               badarg = 1;
+                               }
+                       }
+               args++;
+               }
+
+       if (!ctx)
+               badarg = 1;
+
+       if (badarg)
+               {
+               bad:
+               BIO_printf(bio_err, "Usage genpkey [options]\n");
+               BIO_printf(bio_err, "where options are\n");
+               BIO_printf(bio_err, "-paramfile file parameter file\n");
+               BIO_printf(bio_err, "-pass arg       output file pass phrase source\n");
+               BIO_printf(bio_err, "-outform X      output format (DER or PEM)\n");
+               BIO_printf(bio_err, "-out file       output file\n");
+#ifndef OPENSSL_NO_ENGINE
+               BIO_printf(bio_err, "-engine e       use engine e, possibly a hardware device.\n");
+#endif
+               return 1;
+               }
+
+       if (!app_passwd(bio_err, passarg, NULL, &pass, NULL))
+               {
+               BIO_puts(bio_err, "Error getting password\n");
+               goto end;
+               }
+
+       if (outfile)
+               {
+               if (!(out = BIO_new_file (outfile, "wb")))
+                       {
+                       BIO_printf(bio_err,
+                                "Can't open output file %s\n", outfile);
+                       goto end;
+                       }
+               }
+       else
+               {
+               out = BIO_new_fp (stdout, BIO_NOCLOSE);
+#ifdef OPENSSL_SYS_VMS
+                       {
+                       BIO *tmpbio = BIO_new(BIO_f_linebuffer());
+                       out = BIO_push(tmpbio, out);
+                       }
+#endif
+               }
+
+       EVP_PKEY_CTX_set_cb(ctx, genpkey_cb);
+       EVP_PKEY_CTX_set_app_data(ctx, bio_err);
+
+       if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
+               {
+               BIO_puts(bio_err, "Error generating key\n");
+               goto end;
+               }
+
+       if (outformat == FORMAT_PEM) 
+               PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0,
+                                                               NULL, pass);
+       else if (outformat == FORMAT_ASN1)
+               i2d_PrivateKey_bio(out, pkey);
+       else
+               {
+               BIO_printf(bio_err, "Bad format specified for key\n");
+               goto end;
+               }
+
+
+       if (text)
+               EVP_PKEY_print_private(out, pkey, 0, NULL);
+
+       ret = 0;
+
+       end:
+       if (pkey)
+               EVP_PKEY_free(pkey);
+       if (ctx)
+               EVP_PKEY_CTX_free(ctx);
+       if (out)
+               BIO_free_all(out);
+       BIO_free(in);
+       if (pass)
+               OPENSSL_free(pass);
+
+       return ret;
+       }
+
+static int init_keygen_file(BIO *err, EVP_PKEY_CTX **pctx,
+                               const char *file, ENGINE *e)
+       {
+       BIO *pbio;
+       EVP_PKEY *pkey = NULL;
+       EVP_PKEY_CTX *ctx = NULL;
+       if (*pctx)
+               {
+               BIO_puts(err, "Parameters already set!\n");
+               return 0;
+               }
+
+       pbio = BIO_new_file(file, "r");
+       if (!pbio)
+               {
+               BIO_printf(err, "Can't open parameter file %s\n", file);
+               return 0;
+               }
+
+       pkey = PEM_read_bio_Parameters(pbio, NULL);
+       BIO_free(pbio);
+
+       if (!pkey)
+               {
+               BIO_printf(bio_err, "Error reading parameter file %s\n", file);
+               return 0;
+               }
+
+       ctx = EVP_PKEY_CTX_new(pkey, e);
+       if (!ctx)
+               goto err;
+       if (EVP_PKEY_keygen_init(ctx) <= 0)
+               goto err;
+       EVP_PKEY_free(pkey);
+       *pctx = ctx;
+       return 1;
+
+       err:
+       BIO_puts(err, "Error initializing context\n");
+       ERR_print_errors(err);
+       if (ctx)
+               EVP_PKEY_CTX_free(ctx);
+       if (pkey)
+               EVP_PKEY_free(pkey);
+       return 0;
+
+       }
+
+static int init_gen_str(BIO *err, EVP_PKEY_CTX **pctx,
+                               const char *algname, ENGINE *e, int do_param)
+       {
+       EVP_PKEY_CTX *ctx = NULL;
+       const EVP_PKEY_ASN1_METHOD *ameth;
+       int pkey_id;
+       if (*pctx)
+               {
+               BIO_puts(err, "Algorithm already set!\n");
+               return 0;
+               }
+
+       ameth = EVP_PKEY_asn1_find_str(algname, -1);
+       if (!ameth)
+               {
+               BIO_printf(bio_err, "Algorithm %s not found\n", algname);
+               return 0;
+               }
+
+       EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
+       ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
+
+       if (!ctx)
+               goto err;
+       if (do_param)
+               {
+               if (EVP_PKEY_paramgen_init(ctx) <= 0)
+                       goto err;
+               }
+       else
+               {
+               if (EVP_PKEY_keygen_init(ctx) <= 0)
+                       goto err;
+               }
+
+       *pctx = ctx;
+       return 1;
+
+       err:
+       BIO_printf(err, "Error initializing %s context\n", algname);
+       ERR_print_errors(err);
+       if (ctx)
+               EVP_PKEY_CTX_free(ctx);
+       return 0;
+
+       }
+
+static int genpkey_cb(EVP_PKEY_CTX *ctx)
+       {
+       char c='*';
+       BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
+       int p;
+       p = EVP_PKEY_CTX_get_keygen_info(ctx, 0);
+       if (p == 0) c='.';
+       if (p == 1) c='+';
+       if (p == 2) c='*';
+       if (p == 3) c='\n';
+       BIO_write(b,&c,1);
+       (void)BIO_flush(b);
+#ifdef LINT
+       p=n;
+#endif
+       return 1;
+       }
index 82b59a8..1ecde3c 100644 (file)
@@ -435,7 +435,7 @@ static EVP_PKEY_CTX *init_ctx(int *pkeysize,
        if (!pkey)
                goto end;
 
-       ctx = EVP_PKEY_CTX_new(pkey);
+       ctx = EVP_PKEY_CTX_new(pkey, NULL);
 
        EVP_PKEY_free(pkey);
 
index d5b5995..3458b11 100644 (file)
@@ -22,6 +22,7 @@ extern int ecparam_main(int argc,char *argv[]);
 extern int x509_main(int argc,char *argv[]);
 extern int genrsa_main(int argc,char *argv[]);
 extern int gendsa_main(int argc,char *argv[]);
+extern int genpkey_main(int argc,char *argv[]);
 extern int s_server_main(int argc,char *argv[]);
 extern int s_client_main(int argc,char *argv[]);
 extern int speed_main(int argc,char *argv[]);
@@ -100,6 +101,7 @@ FUNCTION functions[] = {
 #ifndef OPENSSL_NO_DSA
        {FUNC_TYPE_GENERAL,"gendsa",gendsa_main},
 #endif
+       {FUNC_TYPE_GENERAL,"genpkey",genpkey_main},
 #if !defined(OPENSSL_NO_SOCK) && !(defined(OPENSSL_NO_SSL2) && defined(OPENSSL_NO_SSL3))
        {FUNC_TYPE_GENERAL,"s_server",s_server_main},
 #endif
index 14b5aa3..4dd0dfa 100644 (file)
@@ -160,6 +160,8 @@ const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(const char *str, int len)
        {
        int i;
        const EVP_PKEY_ASN1_METHOD *ameth;
+       if (len == -1)
+               len = strlen(str);
        for (i = 0; i < EVP_PKEY_asn1_get_count(); i++)
                {
                ameth = EVP_PKEY_asn1_get0(i);
index cad6e9a..9b8a57f 100644 (file)
@@ -28,7 +28,7 @@ LIBSRC= encode.c digest.c evp_enc.c evp_key.c evp_acnf.c \
        bio_md.c bio_b64.c bio_enc.c evp_err.c e_null.c \
        c_all.c c_allc.c c_alld.c evp_lib.c bio_ok.c \
        evp_pkey.c evp_pbe.c p5_crpt.c p5_crpt2.c \
-       e_old.c pmeth_lib.c pmeth_fn.c
+       e_old.c pmeth_lib.c pmeth_fn.c pmeth_gn.c
 
 LIBOBJ=        encode.o digest.o evp_enc.o evp_key.o evp_acnf.o \
        e_des.o e_bf.o e_idea.o e_des3.o \
@@ -40,7 +40,7 @@ LIBOBJ=       encode.o digest.o evp_enc.o evp_key.o evp_acnf.o \
        bio_md.o bio_b64.o bio_enc.o evp_err.o e_null.o \
        c_all.o c_allc.o c_alld.o evp_lib.o bio_ok.o \
        evp_pkey.o evp_pbe.o p5_crpt.o p5_crpt2.o \
-       e_old.o pmeth_lib.o pmeth_fn.o
+       e_old.o pmeth_lib.o pmeth_fn.o pmeth_gn.o
 
 SRC= $(LIBSRC)
 
index 7d089fe..6ad5464 100644 (file)
@@ -937,7 +937,8 @@ void EVP_PKEY_asn1_set_ctrl(EVP_PKEY_ASN1_METHOD *ameth,
 #define EVP_PKEY_ALG_CTRL              0x1000
 
 const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type, ENGINE *e);
-EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey);
+EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e);
+EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e);
 void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx);
 
 int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
@@ -945,6 +946,10 @@ int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
 int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
                                                const char *value);
 
+void EVP_PKEY_CTX_set_data(EVP_PKEY_CTX *ctx, void *data);
+void *EVP_PKEY_CTX_get_data(EVP_PKEY_CTX *ctx);
+void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data);
+void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx);
 
 int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_sign(EVP_PKEY_CTX *ctx,
@@ -967,6 +972,16 @@ int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx,
                        unsigned char *out, int *outlen,
                        const unsigned char *in, int inlen);
 
+typedef int EVP_PKEY_gen_cb(EVP_PKEY_CTX *ctx);
+
+int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx);
+int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
+int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx);
+int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
+
+void EVP_PKEY_CTX_set_cb(EVP_PKEY_CTX *ctx, EVP_PKEY_gen_cb *cb);
+int EVP_PKEY_CTX_get_keygen_info(EVP_PKEY_CTX *ctx, int idx);
+
 /* BEGIN ERROR CODES */
 /* The following lines are auto generated by the script mkerr.pl. Any changes
  * made after this point may be overwritten when the script is next run.
@@ -1006,7 +1021,11 @@ void ERR_load_EVP_strings(void);
 #define EVP_F_EVP_PKEY_GET1_ECDSA                       130
 #define EVP_F_EVP_PKEY_GET1_EC_KEY                      131
 #define EVP_F_EVP_PKEY_GET1_RSA                                 121
+#define EVP_F_EVP_PKEY_KEYGEN                           146
+#define EVP_F_EVP_PKEY_KEYGEN_INIT                      147
 #define EVP_F_EVP_PKEY_NEW                              106
+#define EVP_F_EVP_PKEY_PARAMGEN                                 148
+#define EVP_F_EVP_PKEY_PARAMGEN_INIT                    149
 #define EVP_F_EVP_PKEY_SIGN                             140
 #define EVP_F_EVP_PKEY_SIGN_INIT                        141
 #define EVP_F_EVP_PKEY_VERIFY                           142
index 0f14fa8..c3e51f8 100644 (file)
@@ -100,7 +100,11 @@ static ERR_STRING_DATA EVP_str_functs[]=
 {ERR_FUNC(EVP_F_EVP_PKEY_GET1_ECDSA),  "EVP_PKEY_GET1_ECDSA"},
 {ERR_FUNC(EVP_F_EVP_PKEY_GET1_EC_KEY), "EVP_PKEY_get1_EC_KEY"},
 {ERR_FUNC(EVP_F_EVP_PKEY_GET1_RSA),    "EVP_PKEY_get1_RSA"},
+{ERR_FUNC(EVP_F_EVP_PKEY_KEYGEN),      "EVP_PKEY_KEYGEN"},
+{ERR_FUNC(EVP_F_EVP_PKEY_KEYGEN_INIT), "EVP_PKEY_KEYGEN_INIT"},
 {ERR_FUNC(EVP_F_EVP_PKEY_NEW), "EVP_PKEY_new"},
+{ERR_FUNC(EVP_F_EVP_PKEY_PARAMGEN),    "EVP_PKEY_PARAMGEN"},
+{ERR_FUNC(EVP_F_EVP_PKEY_PARAMGEN_INIT),       "EVP_PKEY_PARAMGEN_INIT"},
 {ERR_FUNC(EVP_F_EVP_PKEY_SIGN),        "EVP_PKEY_sign"},
 {ERR_FUNC(EVP_F_EVP_PKEY_SIGN_INIT),   "EVP_PKEY_sign_init"},
 {ERR_FUNC(EVP_F_EVP_PKEY_VERIFY),      "EVP_PKEY_verify"},
index 983dae7..3edfd99 100644 (file)
@@ -235,7 +235,6 @@ const EVP_CIPHER *EVP_##cname##_ecb(void) { return &cname##_ecb; }
                             EVP_CIPHER_get_asn1_iv, \
                             NULL)
 
-
 struct evp_pkey_ctx_st
        {
        /* Method associated with this operation */
@@ -246,6 +245,13 @@ struct evp_pkey_ctx_st
        int operation;
        /* Algorithm specific data */
        void *data;
+       /* Application specific data */
+       void *app_data;
+       /* Keygen callback */
+       EVP_PKEY_gen_cb *pkey_gencb;
+       /* implementation specific keygen data */
+       int *keygen_info;
+       int keygen_info_count;
        } /* EVP_PKEY_CTX */;
 
 struct evp_pkey_method_st
@@ -257,10 +263,10 @@ struct evp_pkey_method_st
        void (*cleanup)(EVP_PKEY_CTX *ctx);
 
        int (*paramgen_init)(EVP_PKEY_CTX *ctx);
-       int (*paramgen)(EVP_PKEY_CTX *ctx);
+       int (*paramgen)(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey);
 
        int (*keygen_init)(EVP_PKEY_CTX *ctx);
-       int (*keygen)(EVP_PKEY_CTX *ctx);
+       int (*keygen)(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey);
 
        int (*sign_init)(EVP_PKEY_CTX *ctx);
        int (*sign)(EVP_PKEY_CTX *ctx, unsigned char *sig, int *siglen,
@@ -296,3 +302,5 @@ struct evp_pkey_method_st
 
 
        } /* EVP_PKEY_METHOD */;
+
+void evp_pkey_set_cb_translate(BN_GENCB *cb, EVP_PKEY_CTX *ctx);
diff --git a/crypto/evp/pmeth_gn.c b/crypto/evp/pmeth_gn.c
new file mode 100644 (file)
index 0000000..4972d5e
--- /dev/null
@@ -0,0 +1,193 @@
+/* pmeth_gn.c */
+/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <openssl/objects.h>
+#include "cryptlib.h"
+#include <openssl/evp.h>
+#include "evp_locl.h"
+
+int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx)
+       {
+       int ret;
+       if (!ctx || !ctx->pmeth || !ctx->pmeth->paramgen)
+               {
+               EVPerr(EVP_F_EVP_PKEY_PARAMGEN_INIT,
+                       EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+               return -2;
+               }
+       ctx->operation = EVP_PKEY_OP_PARAMGEN;
+       if (!ctx->pmeth->paramgen_init)
+               return 1;
+       ret = ctx->pmeth->paramgen_init(ctx);
+       if (ret <= 0)
+               ctx->operation = EVP_PKEY_OP_UNDEFINED;
+       return ret;
+       }
+
+int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey)
+       {
+       int ret;
+       if (!ctx || !ctx->pmeth || !ctx->pmeth->paramgen)
+               {
+               EVPerr(EVP_F_EVP_PKEY_PARAMGEN,
+                       EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+               return -2;
+               }
+
+       if (ctx->operation != EVP_PKEY_OP_PARAMGEN)
+               {
+               EVPerr(EVP_F_EVP_PKEY_PARAMGEN, EVP_R_OPERATON_NOT_INITIALIZED);
+               return -1;
+               }
+
+       if (!ppkey)
+               return -1;
+
+       if (!*ppkey)
+               *ppkey = EVP_PKEY_new();
+
+       ret = ctx->pmeth->paramgen(ctx, *ppkey);
+       if (ret <= 0)
+               {
+               EVP_PKEY_free(*ppkey);
+               *ppkey = NULL;
+               }
+       return ret;
+       }
+
+int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx)
+       {
+       int ret;
+       if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen)
+               {
+               EVPerr(EVP_F_EVP_PKEY_KEYGEN_INIT,
+                       EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+               return -2;
+               }
+       ctx->operation = EVP_PKEY_OP_KEYGEN;
+       if (!ctx->pmeth->keygen_init)
+               return 1;
+       ret = ctx->pmeth->keygen_init(ctx);
+       if (ret <= 0)
+               ctx->operation = EVP_PKEY_OP_UNDEFINED;
+       return ret;
+       }
+
+int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey)
+       {
+       int ret;
+
+       if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen)
+               {
+               EVPerr(EVP_F_EVP_PKEY_KEYGEN,
+                       EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+               return -2;
+               }
+       if (ctx->operation != EVP_PKEY_OP_KEYGEN)
+               {
+               EVPerr(EVP_F_EVP_PKEY_KEYGEN, EVP_R_OPERATON_NOT_INITIALIZED);
+               return -1;
+               }
+
+       if (!ppkey)
+               return -1;
+
+       if (!*ppkey)
+               *ppkey = EVP_PKEY_new();
+
+       ret = ctx->pmeth->keygen(ctx, *ppkey);
+       if (ret <= 0)
+               {
+               EVP_PKEY_free(*ppkey);
+               *ppkey = NULL;
+               }
+       return ret;
+       }
+
+void EVP_PKEY_CTX_set_cb(EVP_PKEY_CTX *ctx, EVP_PKEY_gen_cb *cb)
+       {
+       ctx->pkey_gencb = cb;
+       }
+
+/* "translation callback" to call EVP_PKEY_CTX callbacks using BN_GENCB
+ * style callbacks.
+ */
+
+static int trans_cb(int a, int b, BN_GENCB *gcb)
+       {
+       EVP_PKEY_CTX *ctx = gcb->arg;
+       ctx->keygen_info[0] = a;
+       ctx->keygen_info[1] = b;
+       return ctx->pkey_gencb(ctx);
+       }       
+
+void evp_pkey_set_cb_translate(BN_GENCB *cb, EVP_PKEY_CTX *ctx)
+       {
+       BN_GENCB_set(cb, trans_cb, ctx)
+       }
+
+int EVP_PKEY_CTX_get_keygen_info(EVP_PKEY_CTX *ctx, int idx)
+       {
+       if (idx == -1)
+               return ctx->keygen_info_count; 
+       if (idx < 0 || idx > ctx->keygen_info_count)
+               return 0;
+       return ctx->keygen_info[idx];
+       }
index 26a5504..3c8d0a6 100644 (file)
@@ -101,20 +101,25 @@ const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type, ENGINE *e)
        return *ret;
        }
 
-EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey)
+static EVP_PKEY_CTX *int_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id)
        {
        EVP_PKEY_CTX *ret;
        const EVP_PKEY_METHOD *pmeth;
-       if (!pkey || !pkey->ameth)
-               return NULL;
-       pmeth = EVP_PKEY_meth_find(pkey->ameth->pkey_id, NULL);
+       if (id == -1)
+               {
+               if (!pkey || !pkey->ameth)
+                       return NULL;
+               id = pkey->ameth->pkey_id;
+               }
+       pmeth = EVP_PKEY_meth_find(id, e);
        if (pmeth == NULL)
                return NULL;
        ret = OPENSSL_malloc(sizeof(EVP_PKEY_CTX));
        ret->pmeth = pmeth;
        ret->operation = EVP_PKEY_OP_UNDEFINED;
-       CRYPTO_add(&pkey->references,1,CRYPTO_LOCK_EVP_PKEY);
        ret->pkey = pkey;
+       if (pkey)
+               CRYPTO_add(&pkey->references,1,CRYPTO_LOCK_EVP_PKEY);
        ret->data = NULL;
 
        if (pmeth->init)
@@ -129,6 +134,16 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey)
        return ret;
        }
 
+EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e)
+       {
+       return int_ctx_new(pkey, e, -1);
+       }
+
+EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e)
+       {
+       return int_ctx_new(NULL, e, id);
+       }
+
 void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx)
        {
        if (ctx->pmeth && ctx->pmeth->cleanup)
@@ -191,3 +206,23 @@ int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx,
                }
        return ctx->pmeth->ctrl_str(ctx, name, value);
        }
+
+void EVP_PKEY_CTX_set_data(EVP_PKEY_CTX *ctx, void *data)
+       {
+       ctx->data = data;
+       }
+
+void *EVP_PKEY_CTX_get_data(EVP_PKEY_CTX *ctx)
+       {
+       return ctx->data;
+       }
+
+void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data)
+       {
+       ctx->app_data = data;
+       }
+
+void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx)
+       {
+       return ctx->app_data;
+       }
index 378bfe4..56759b5 100644 (file)
@@ -75,6 +75,8 @@ typedef struct
        /* Key gen parameters */
        int nbits;
        BIGNUM *pub_exp;
+       /* Keygen callback info */
+       int gentmp[2];
        /* RSA padding mode */
        int pad_mode;
        /* message digest */
@@ -100,6 +102,8 @@ static int pkey_rsa_init(EVP_PKEY_CTX *ctx)
        rctx->saltlen = -2;
 
        ctx->data = rctx;
+       ctx->keygen_info = rctx->gentmp;
+       ctx->keygen_info_count = 2;
        
        return 1;
        }
@@ -427,6 +431,36 @@ static int pkey_rsa_ctrl_str(EVP_PKEY_CTX *ctx,
        return -2;
        }
 
+static int pkey_rsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
+       {
+       RSA *rsa = NULL;
+       RSA_PKEY_CTX *rctx = ctx->data;
+       BN_GENCB *pcb, cb;
+       int ret;
+       if (!rctx->pub_exp)
+               {
+               rctx->pub_exp = BN_new();
+               if (!rctx->pub_exp || !BN_set_word(rctx->pub_exp, RSA_F4))
+                       return 0;
+               }
+       rsa = RSA_new();
+       if (!rsa)
+               return 0;
+       if (ctx->pkey_gencb)
+               {
+               pcb = &cb;
+               evp_pkey_set_cb_translate(pcb, ctx);
+               }
+       else
+               pcb = NULL;
+       ret = RSA_generate_key_ex(rsa, rctx->nbits, rctx->pub_exp, pcb);
+       if (ret > 0)
+               EVP_PKEY_assign_RSA(pkey, rsa);
+       else
+               RSA_free(rsa);
+       return ret;
+       }
+
 const EVP_PKEY_METHOD rsa_pkey_meth = 
        {
        EVP_PKEY_RSA,
@@ -436,7 +470,8 @@ const EVP_PKEY_METHOD rsa_pkey_meth =
 
        0,0,
 
-       0,0,
+       0,
+       pkey_rsa_keygen,
 
        0,
        pkey_rsa_sign,