static int pkey_rsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
{
    RSA *rsa = NULL;
    RSA_PKEY_CTX *rctx = ctx->data;
    BN_GENCB *pcb;
    int ret;

    if (rctx->pub_exp == NULL) {
        rctx->pub_exp = BN_new();
        if (rctx->pub_exp == NULL || !BN_set_word(rctx->pub_exp, RSA_F4))
            return 0;
    }
    rsa = RSA_new();
    if (rsa == NULL)
        return 0;
    if (ctx->pkey_gencb) {
        pcb = BN_GENCB_new();
        if (pcb == NULL) {
            RSA_free(rsa);
            return 0;
        }
        evp_pkey_set_cb_translate(pcb, ctx);
    } else {
        pcb = NULL;
    }
    ret = RSA_generate_multi_prime_key(rsa, rctx->nbits, rctx->primes,
                                       rctx->pub_exp, pcb);
    BN_GENCB_free(pcb);
    if (ret > 0 && !rsa_set_pss_param(rsa, ctx)) {
        RSA_free(rsa);
        return 0;
    }
    if (ret > 0)
        EVP_PKEY_assign(pkey, ctx->pmeth->pkey_id, rsa);
    else
        RSA_free(rsa);
    return ret;
}
int MAIN(int argc, char **argv)
	{
	BN_GENCB cb;
#ifndef OPENSSL_NO_ENGINE
	ENGINE *e = NULL;
#endif
	int ret=1;
	int i,num=DEFBITS;
	int num_primes=2;
	long l;
	const EVP_CIPHER *enc=NULL;
	unsigned long f4=RSA_F4;
	char *outfile=NULL;
	char *passargout = NULL, *passout = NULL;
#ifndef OPENSSL_NO_ENGINE
	char *engine=NULL;
#endif
	char *inrand=NULL;
	BIO *out=NULL;
	BIGNUM *bn = BN_new();
	RSA *rsa = NULL;

	if(!bn) goto err;

	apps_startup();
	BN_GENCB_set(&cb, genrsa_cb, bio_err);

	if (bio_err == NULL)
		if ((bio_err=BIO_new(BIO_s_file())) != NULL)
			BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);

	if (!load_config(bio_err, NULL))
		goto err;
	if ((out=BIO_new(BIO_s_file())) == NULL)
		{
		BIO_printf(bio_err,"unable to create BIO for output\n");
		goto err;
		}

	argv++;
	argc--;
	for (;;)
		{
		if (argc <= 0) break;
		if (strcmp(*argv,"-out") == 0)
			{
			if (--argc < 1) goto bad;
			outfile= *(++argv);
			}
		else if (strcmp(*argv,"-3") == 0)
			f4=3;
		else if (strcmp(*argv,"-F4") == 0 || strcmp(*argv,"-f4") == 0)
			f4=RSA_F4;
#ifndef OPENSSL_NO_ENGINE
		else if (strcmp(*argv,"-engine") == 0)
			{
			if (--argc < 1) goto bad;
			engine= *(++argv);
			}
#endif
		else if (strcmp(*argv,"-rand") == 0)
			{
			if (--argc < 1) goto bad;
			inrand= *(++argv);
			}
#ifndef OPENSSL_NO_DES
		else if (strcmp(*argv,"-des") == 0)
			enc=EVP_des_cbc();
		else if (strcmp(*argv,"-des3") == 0)
			enc=EVP_des_ede3_cbc();
#endif
#ifndef OPENSSL_NO_IDEA
		else if (strcmp(*argv,"-idea") == 0)
			enc=EVP_idea_cbc();
#endif
#ifndef OPENSSL_NO_SEED
		else if (strcmp(*argv,"-seed") == 0)
			enc=EVP_seed_cbc();
#endif
#ifndef OPENSSL_NO_AES
		else if (strcmp(*argv,"-aes128") == 0)
			enc=EVP_aes_128_cbc();
		else if (strcmp(*argv,"-aes192") == 0)
			enc=EVP_aes_192_cbc();
		else if (strcmp(*argv,"-aes256") == 0)
			enc=EVP_aes_256_cbc();
#endif
#ifndef OPENSSL_NO_CAMELLIA
		else if (strcmp(*argv,"-camellia128") == 0)
			enc=EVP_camellia_128_cbc();
		else if (strcmp(*argv,"-camellia192") == 0)
			enc=EVP_camellia_192_cbc();
		else if (strcmp(*argv,"-camellia256") == 0)
			enc=EVP_camellia_256_cbc();
#endif
		else if (strcmp(*argv,"-passout") == 0)
			{
			if (--argc < 1) goto bad;
			passargout= *(++argv);
			}
		else if (strcmp(*argv,"-nprimes") == 0)
			{
			if (--argc < 1) goto bad;
			if (sscanf(*(++argv), "%d", &num_primes) != 1) goto bad;
			if (num_primes < 2) goto bad;
			}
		else
			break;
		argv++;
		argc--;
		}
	if ((argc >= 1) && ((sscanf(*argv,"%d",&num) == 0) || (num < 0)))
		{
bad:
		BIO_printf(bio_err,"usage: genrsa [args] [numbits]\n");
		BIO_printf(bio_err," -des            encrypt the generated key with DES in cbc mode\n");
		BIO_printf(bio_err," -des3           encrypt the generated key with DES in ede cbc mode (168 bit key)\n");
#ifndef OPENSSL_NO_IDEA
		BIO_printf(bio_err," -idea           encrypt the generated key with IDEA in cbc mode\n");
#endif
#ifndef OPENSSL_NO_SEED
		BIO_printf(bio_err," -seed\n");
		BIO_printf(bio_err,"                 encrypt PEM output with cbc seed\n");
#endif
#ifndef OPENSSL_NO_AES
		BIO_printf(bio_err," -aes128, -aes192, -aes256\n");
		BIO_printf(bio_err,"                 encrypt PEM output with cbc aes\n");
#endif
#ifndef OPENSSL_NO_CAMELLIA
		BIO_printf(bio_err," -camellia128, -camellia192, -camellia256\n");
		BIO_printf(bio_err,"                 encrypt PEM output with cbc camellia\n");
#endif
		BIO_printf(bio_err," -out file       output the key to 'file\n");
		BIO_printf(bio_err," -passout arg    output file pass phrase source\n");
		BIO_printf(bio_err," -f4             use F4 (0x10001) for the E value\n");
		BIO_printf(bio_err," -3              use 3 for the E value\n");
#ifndef OPENSSL_NO_ENGINE
		BIO_printf(bio_err," -engine e       use engine e, possibly a hardware device.\n");
#endif
		BIO_printf(bio_err," -rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR);
		BIO_printf(bio_err,"                 load the file (or the files in the directory) into\n");
		BIO_printf(bio_err,"                 the random number generator\n");
		BIO_printf(bio_err," -nprimes n      number of primes to use (>= 2)\n");
		goto err;
		}
		
	ERR_load_crypto_strings();

	if(!app_passwd(bio_err, NULL, passargout, NULL, &passout)) {
		BIO_printf(bio_err, "Error getting password\n");
		goto err;
	}

#ifndef OPENSSL_NO_ENGINE
        e = setup_engine(bio_err, engine, 0);
#endif

	if (outfile == NULL)
		{
		BIO_set_fp(out,stdout,BIO_NOCLOSE);
#ifdef OPENSSL_SYS_VMS
		{
		BIO *tmpbio = BIO_new(BIO_f_linebuffer());
		out = BIO_push(tmpbio, out);
		}
#endif
		}
	else
		{
		if (BIO_write_filename(out,outfile) <= 0)
			{
			perror(outfile);
			goto err;
			}
		}

	if (!app_RAND_load_file(NULL, bio_err, 1) && inrand == NULL
		&& !RAND_status())
		{
		BIO_printf(bio_err,"warning, not much extra random data, consider using the -rand option\n");
		}
	if (inrand != NULL)
		BIO_printf(bio_err,"%ld semi-random bytes loaded\n",
			app_RAND_load_files(inrand));

	BIO_printf(bio_err,"Generating RSA private key, %d bit long modulus\n",
		num);
#ifdef OPENSSL_NO_ENGINE
	rsa = RSA_new();
#else
	rsa = RSA_new_method(e);
#endif
	if (!rsa)
		goto err;

	if(!BN_set_word(bn, f4) || !RSA_generate_multi_prime_key(rsa, num, num_primes, bn, &cb))
		goto err;
		
	app_RAND_write_file(NULL, bio_err);

	/* We need to do the following for when the base number size is <
	 * long, esp windows 3.1 :-(. */
	l=0L;
	for (i=0; i<rsa->e->top; i++)
		{
#ifndef SIXTY_FOUR_BIT
		l<<=BN_BITS4;
		l<<=BN_BITS4;
#endif
		l+=rsa->e->d[i];
		}
	BIO_printf(bio_err,"e is %ld (0x%lX)\n",l,l);
	{
	PW_CB_DATA cb_data;
	cb_data.password = passout;
	cb_data.prompt_info = outfile;
	if (!PEM_write_bio_RSAPrivateKey(out,rsa,enc,NULL,0,
		(pem_password_cb *)password_callback,&cb_data))
		goto err;
	}

	ret=0;
err:
	if (bn) BN_free(bn);
	if (rsa) RSA_free(rsa);
	if (out) BIO_free_all(out);
	if(passout) OPENSSL_free(passout);
	if (ret != 0)
		ERR_print_errors(bio_err);
	apps_shutdown();
	OPENSSL_EXIT(ret);
	}