11cb0ef41Sopenharmony_ci/*
21cb0ef41Sopenharmony_ci * Copyright 2006-2023 The OpenSSL Project Authors. All Rights Reserved.
31cb0ef41Sopenharmony_ci *
41cb0ef41Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
51cb0ef41Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
61cb0ef41Sopenharmony_ci * in the file LICENSE in the source distribution or at
71cb0ef41Sopenharmony_ci * https://www.openssl.org/source/license.html
81cb0ef41Sopenharmony_ci */
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci#include <stdio.h>
111cb0ef41Sopenharmony_ci#include <string.h>
121cb0ef41Sopenharmony_ci#include "apps.h"
131cb0ef41Sopenharmony_ci#include "progs.h"
141cb0ef41Sopenharmony_ci#include <openssl/pem.h>
151cb0ef41Sopenharmony_ci#include <openssl/err.h>
161cb0ef41Sopenharmony_ci#include <openssl/evp.h>
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_cistatic int quiet;
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_cistatic int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e,
211cb0ef41Sopenharmony_ci                            OSSL_LIB_CTX *libctx, const char *propq);
221cb0ef41Sopenharmony_cistatic int genpkey_cb(EVP_PKEY_CTX *ctx);
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_citypedef enum OPTION_choice {
251cb0ef41Sopenharmony_ci    OPT_COMMON,
261cb0ef41Sopenharmony_ci    OPT_ENGINE, OPT_OUTFORM, OPT_OUT, OPT_PASS, OPT_PARAMFILE,
271cb0ef41Sopenharmony_ci    OPT_ALGORITHM, OPT_PKEYOPT, OPT_GENPARAM, OPT_TEXT, OPT_CIPHER,
281cb0ef41Sopenharmony_ci    OPT_QUIET, OPT_CONFIG,
291cb0ef41Sopenharmony_ci    OPT_PROV_ENUM
301cb0ef41Sopenharmony_ci} OPTION_CHOICE;
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ciconst OPTIONS genpkey_options[] = {
331cb0ef41Sopenharmony_ci    OPT_SECTION("General"),
341cb0ef41Sopenharmony_ci    {"help", OPT_HELP, '-', "Display this summary"},
351cb0ef41Sopenharmony_ci#ifndef OPENSSL_NO_ENGINE
361cb0ef41Sopenharmony_ci    {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
371cb0ef41Sopenharmony_ci#endif
381cb0ef41Sopenharmony_ci    {"paramfile", OPT_PARAMFILE, '<', "Parameters file"},
391cb0ef41Sopenharmony_ci    {"algorithm", OPT_ALGORITHM, 's', "The public key algorithm"},
401cb0ef41Sopenharmony_ci    {"quiet", OPT_QUIET, '-', "Do not output status while generating keys"},
411cb0ef41Sopenharmony_ci    {"pkeyopt", OPT_PKEYOPT, 's',
421cb0ef41Sopenharmony_ci     "Set the public key algorithm option as opt:value"},
431cb0ef41Sopenharmony_ci     OPT_CONFIG_OPTION,
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci    OPT_SECTION("Output"),
461cb0ef41Sopenharmony_ci    {"out", OPT_OUT, '>', "Output file"},
471cb0ef41Sopenharmony_ci    {"outform", OPT_OUTFORM, 'F', "output format (DER or PEM)"},
481cb0ef41Sopenharmony_ci    {"pass", OPT_PASS, 's', "Output file pass phrase source"},
491cb0ef41Sopenharmony_ci    {"genparam", OPT_GENPARAM, '-', "Generate parameters, not key"},
501cb0ef41Sopenharmony_ci    {"text", OPT_TEXT, '-', "Print the in text"},
511cb0ef41Sopenharmony_ci    {"", OPT_CIPHER, '-', "Cipher to use to encrypt the key"},
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci    OPT_PROV_OPTIONS,
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci    /* This is deliberately last. */
561cb0ef41Sopenharmony_ci    {OPT_HELP_STR, 1, 1,
571cb0ef41Sopenharmony_ci     "Order of options may be important!  See the documentation.\n"},
581cb0ef41Sopenharmony_ci    {NULL}
591cb0ef41Sopenharmony_ci};
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ciint genpkey_main(int argc, char **argv)
621cb0ef41Sopenharmony_ci{
631cb0ef41Sopenharmony_ci    CONF *conf = NULL;
641cb0ef41Sopenharmony_ci    BIO *in = NULL, *out = NULL;
651cb0ef41Sopenharmony_ci    ENGINE *e = NULL;
661cb0ef41Sopenharmony_ci    EVP_PKEY *pkey = NULL;
671cb0ef41Sopenharmony_ci    EVP_PKEY_CTX *ctx = NULL;
681cb0ef41Sopenharmony_ci    char *outfile = NULL, *passarg = NULL, *pass = NULL, *prog, *p;
691cb0ef41Sopenharmony_ci    const char *ciphername = NULL, *paramfile = NULL, *algname = NULL;
701cb0ef41Sopenharmony_ci    EVP_CIPHER *cipher = NULL;
711cb0ef41Sopenharmony_ci    OPTION_CHOICE o;
721cb0ef41Sopenharmony_ci    int outformat = FORMAT_PEM, text = 0, ret = 1, rv, do_param = 0;
731cb0ef41Sopenharmony_ci    int private = 0, i;
741cb0ef41Sopenharmony_ci    OSSL_LIB_CTX *libctx = app_get0_libctx();
751cb0ef41Sopenharmony_ci    STACK_OF(OPENSSL_STRING) *keyopt = NULL;
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci    prog = opt_init(argc, argv, genpkey_options);
781cb0ef41Sopenharmony_ci    keyopt = sk_OPENSSL_STRING_new_null();
791cb0ef41Sopenharmony_ci    if (keyopt == NULL)
801cb0ef41Sopenharmony_ci        goto end;
811cb0ef41Sopenharmony_ci    while ((o = opt_next()) != OPT_EOF) {
821cb0ef41Sopenharmony_ci        switch (o) {
831cb0ef41Sopenharmony_ci        case OPT_EOF:
841cb0ef41Sopenharmony_ci        case OPT_ERR:
851cb0ef41Sopenharmony_ci opthelp:
861cb0ef41Sopenharmony_ci            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
871cb0ef41Sopenharmony_ci            goto end;
881cb0ef41Sopenharmony_ci        case OPT_HELP:
891cb0ef41Sopenharmony_ci            ret = 0;
901cb0ef41Sopenharmony_ci            opt_help(genpkey_options);
911cb0ef41Sopenharmony_ci            goto end;
921cb0ef41Sopenharmony_ci        case OPT_OUTFORM:
931cb0ef41Sopenharmony_ci            if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &outformat))
941cb0ef41Sopenharmony_ci                goto opthelp;
951cb0ef41Sopenharmony_ci            break;
961cb0ef41Sopenharmony_ci        case OPT_OUT:
971cb0ef41Sopenharmony_ci            outfile = opt_arg();
981cb0ef41Sopenharmony_ci            break;
991cb0ef41Sopenharmony_ci        case OPT_PASS:
1001cb0ef41Sopenharmony_ci            passarg = opt_arg();
1011cb0ef41Sopenharmony_ci            break;
1021cb0ef41Sopenharmony_ci        case OPT_ENGINE:
1031cb0ef41Sopenharmony_ci            e = setup_engine(opt_arg(), 0);
1041cb0ef41Sopenharmony_ci            break;
1051cb0ef41Sopenharmony_ci        case OPT_PARAMFILE:
1061cb0ef41Sopenharmony_ci            if (do_param == 1)
1071cb0ef41Sopenharmony_ci                goto opthelp;
1081cb0ef41Sopenharmony_ci            paramfile = opt_arg();
1091cb0ef41Sopenharmony_ci            break;
1101cb0ef41Sopenharmony_ci        case OPT_ALGORITHM:
1111cb0ef41Sopenharmony_ci            algname = opt_arg();
1121cb0ef41Sopenharmony_ci            break;
1131cb0ef41Sopenharmony_ci        case OPT_PKEYOPT:
1141cb0ef41Sopenharmony_ci            if (!sk_OPENSSL_STRING_push(keyopt, opt_arg()))
1151cb0ef41Sopenharmony_ci                goto end;
1161cb0ef41Sopenharmony_ci            break;
1171cb0ef41Sopenharmony_ci        case OPT_QUIET:
1181cb0ef41Sopenharmony_ci            quiet = 1;
1191cb0ef41Sopenharmony_ci            break;
1201cb0ef41Sopenharmony_ci        case OPT_GENPARAM:
1211cb0ef41Sopenharmony_ci            do_param = 1;
1221cb0ef41Sopenharmony_ci            break;
1231cb0ef41Sopenharmony_ci        case OPT_TEXT:
1241cb0ef41Sopenharmony_ci            text = 1;
1251cb0ef41Sopenharmony_ci            break;
1261cb0ef41Sopenharmony_ci        case OPT_CIPHER:
1271cb0ef41Sopenharmony_ci            ciphername = opt_unknown();
1281cb0ef41Sopenharmony_ci            break;
1291cb0ef41Sopenharmony_ci        case OPT_CONFIG:
1301cb0ef41Sopenharmony_ci            conf = app_load_config_modules(opt_arg());
1311cb0ef41Sopenharmony_ci            if (conf == NULL)
1321cb0ef41Sopenharmony_ci                goto end;
1331cb0ef41Sopenharmony_ci            break;
1341cb0ef41Sopenharmony_ci        case OPT_PROV_CASES:
1351cb0ef41Sopenharmony_ci            if (!opt_provider(o))
1361cb0ef41Sopenharmony_ci                goto end;
1371cb0ef41Sopenharmony_ci            break;
1381cb0ef41Sopenharmony_ci        }
1391cb0ef41Sopenharmony_ci    }
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci    /* No extra arguments. */
1421cb0ef41Sopenharmony_ci    argc = opt_num_rest();
1431cb0ef41Sopenharmony_ci    if (argc != 0)
1441cb0ef41Sopenharmony_ci        goto opthelp;
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci    /* Fetch cipher, etc. */
1471cb0ef41Sopenharmony_ci    if (paramfile != NULL) {
1481cb0ef41Sopenharmony_ci        if (!init_keygen_file(&ctx, paramfile, e, libctx, app_get0_propq()))
1491cb0ef41Sopenharmony_ci            goto end;
1501cb0ef41Sopenharmony_ci    }
1511cb0ef41Sopenharmony_ci    if (algname != NULL) {
1521cb0ef41Sopenharmony_ci        if (!init_gen_str(&ctx, algname, e, do_param, libctx, app_get0_propq()))
1531cb0ef41Sopenharmony_ci            goto end;
1541cb0ef41Sopenharmony_ci    }
1551cb0ef41Sopenharmony_ci    if (ctx == NULL)
1561cb0ef41Sopenharmony_ci        goto opthelp;
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_ci    for (i = 0; i < sk_OPENSSL_STRING_num(keyopt); i++) {
1591cb0ef41Sopenharmony_ci        p = sk_OPENSSL_STRING_value(keyopt, i);
1601cb0ef41Sopenharmony_ci        if (pkey_ctrl_string(ctx, p) <= 0) {
1611cb0ef41Sopenharmony_ci            BIO_printf(bio_err, "%s: Error setting %s parameter:\n", prog, p);
1621cb0ef41Sopenharmony_ci            ERR_print_errors(bio_err);
1631cb0ef41Sopenharmony_ci            goto end;
1641cb0ef41Sopenharmony_ci        }
1651cb0ef41Sopenharmony_ci    }
1661cb0ef41Sopenharmony_ci    if (ciphername != NULL)
1671cb0ef41Sopenharmony_ci        if (!opt_cipher(ciphername, &cipher) || do_param == 1)
1681cb0ef41Sopenharmony_ci            goto opthelp;
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci    private = do_param ? 0 : 1;
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_ci    if (!app_passwd(passarg, NULL, &pass, NULL)) {
1731cb0ef41Sopenharmony_ci        BIO_puts(bio_err, "Error getting password\n");
1741cb0ef41Sopenharmony_ci        goto end;
1751cb0ef41Sopenharmony_ci    }
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci    out = bio_open_owner(outfile, outformat, private);
1781cb0ef41Sopenharmony_ci    if (out == NULL)
1791cb0ef41Sopenharmony_ci        goto end;
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci    EVP_PKEY_CTX_set_cb(ctx, genpkey_cb);
1821cb0ef41Sopenharmony_ci    EVP_PKEY_CTX_set_app_data(ctx, bio_err);
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci    pkey = do_param ? app_paramgen(ctx, algname)
1851cb0ef41Sopenharmony_ci                    : app_keygen(ctx, algname, 0, 0 /* not verbose */);
1861cb0ef41Sopenharmony_ci    if (pkey == NULL)
1871cb0ef41Sopenharmony_ci        goto end;
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_ci    if (do_param) {
1901cb0ef41Sopenharmony_ci        rv = PEM_write_bio_Parameters(out, pkey);
1911cb0ef41Sopenharmony_ci    } else if (outformat == FORMAT_PEM) {
1921cb0ef41Sopenharmony_ci        assert(private);
1931cb0ef41Sopenharmony_ci        rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, NULL, pass);
1941cb0ef41Sopenharmony_ci    } else if (outformat == FORMAT_ASN1) {
1951cb0ef41Sopenharmony_ci        assert(private);
1961cb0ef41Sopenharmony_ci        rv = i2d_PrivateKey_bio(out, pkey);
1971cb0ef41Sopenharmony_ci    } else {
1981cb0ef41Sopenharmony_ci        BIO_printf(bio_err, "Bad format specified for key\n");
1991cb0ef41Sopenharmony_ci        goto end;
2001cb0ef41Sopenharmony_ci    }
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci    ret = 0;
2031cb0ef41Sopenharmony_ci
2041cb0ef41Sopenharmony_ci    if (rv <= 0) {
2051cb0ef41Sopenharmony_ci        BIO_puts(bio_err, "Error writing key\n");
2061cb0ef41Sopenharmony_ci        ret = 1;
2071cb0ef41Sopenharmony_ci    }
2081cb0ef41Sopenharmony_ci
2091cb0ef41Sopenharmony_ci    if (text) {
2101cb0ef41Sopenharmony_ci        if (do_param)
2111cb0ef41Sopenharmony_ci            rv = EVP_PKEY_print_params(out, pkey, 0, NULL);
2121cb0ef41Sopenharmony_ci        else
2131cb0ef41Sopenharmony_ci            rv = EVP_PKEY_print_private(out, pkey, 0, NULL);
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_ci        if (rv <= 0) {
2161cb0ef41Sopenharmony_ci            BIO_puts(bio_err, "Error printing key\n");
2171cb0ef41Sopenharmony_ci            ret = 1;
2181cb0ef41Sopenharmony_ci        }
2191cb0ef41Sopenharmony_ci    }
2201cb0ef41Sopenharmony_ci
2211cb0ef41Sopenharmony_ci end:
2221cb0ef41Sopenharmony_ci    sk_OPENSSL_STRING_free(keyopt);
2231cb0ef41Sopenharmony_ci    if (ret != 0)
2241cb0ef41Sopenharmony_ci        ERR_print_errors(bio_err);
2251cb0ef41Sopenharmony_ci    EVP_PKEY_free(pkey);
2261cb0ef41Sopenharmony_ci    EVP_PKEY_CTX_free(ctx);
2271cb0ef41Sopenharmony_ci    EVP_CIPHER_free(cipher);
2281cb0ef41Sopenharmony_ci    BIO_free_all(out);
2291cb0ef41Sopenharmony_ci    BIO_free(in);
2301cb0ef41Sopenharmony_ci    release_engine(e);
2311cb0ef41Sopenharmony_ci    OPENSSL_free(pass);
2321cb0ef41Sopenharmony_ci    NCONF_free(conf);
2331cb0ef41Sopenharmony_ci    return ret;
2341cb0ef41Sopenharmony_ci}
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_cistatic int init_keygen_file(EVP_PKEY_CTX **pctx, const char *file, ENGINE *e,
2371cb0ef41Sopenharmony_ci                            OSSL_LIB_CTX *libctx, const char *propq)
2381cb0ef41Sopenharmony_ci{
2391cb0ef41Sopenharmony_ci    BIO *pbio;
2401cb0ef41Sopenharmony_ci    EVP_PKEY *pkey = NULL;
2411cb0ef41Sopenharmony_ci    EVP_PKEY_CTX *ctx = NULL;
2421cb0ef41Sopenharmony_ci    if (*pctx) {
2431cb0ef41Sopenharmony_ci        BIO_puts(bio_err, "Parameters already set!\n");
2441cb0ef41Sopenharmony_ci        return 0;
2451cb0ef41Sopenharmony_ci    }
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_ci    pbio = BIO_new_file(file, "r");
2481cb0ef41Sopenharmony_ci    if (pbio == NULL) {
2491cb0ef41Sopenharmony_ci        BIO_printf(bio_err, "Can't open parameter file %s\n", file);
2501cb0ef41Sopenharmony_ci        return 0;
2511cb0ef41Sopenharmony_ci    }
2521cb0ef41Sopenharmony_ci
2531cb0ef41Sopenharmony_ci    pkey = PEM_read_bio_Parameters_ex(pbio, NULL, libctx, propq);
2541cb0ef41Sopenharmony_ci    BIO_free(pbio);
2551cb0ef41Sopenharmony_ci
2561cb0ef41Sopenharmony_ci    if (pkey == NULL) {
2571cb0ef41Sopenharmony_ci        BIO_printf(bio_err, "Error reading parameter file %s\n", file);
2581cb0ef41Sopenharmony_ci        return 0;
2591cb0ef41Sopenharmony_ci    }
2601cb0ef41Sopenharmony_ci
2611cb0ef41Sopenharmony_ci    if (e != NULL)
2621cb0ef41Sopenharmony_ci        ctx = EVP_PKEY_CTX_new(pkey, e);
2631cb0ef41Sopenharmony_ci    else
2641cb0ef41Sopenharmony_ci        ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq);
2651cb0ef41Sopenharmony_ci    if (ctx == NULL)
2661cb0ef41Sopenharmony_ci        goto err;
2671cb0ef41Sopenharmony_ci    if (EVP_PKEY_keygen_init(ctx) <= 0)
2681cb0ef41Sopenharmony_ci        goto err;
2691cb0ef41Sopenharmony_ci    EVP_PKEY_free(pkey);
2701cb0ef41Sopenharmony_ci    *pctx = ctx;
2711cb0ef41Sopenharmony_ci    return 1;
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_ci err:
2741cb0ef41Sopenharmony_ci    BIO_puts(bio_err, "Error initializing context\n");
2751cb0ef41Sopenharmony_ci    ERR_print_errors(bio_err);
2761cb0ef41Sopenharmony_ci    EVP_PKEY_CTX_free(ctx);
2771cb0ef41Sopenharmony_ci    EVP_PKEY_free(pkey);
2781cb0ef41Sopenharmony_ci    return 0;
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_ci}
2811cb0ef41Sopenharmony_ci
2821cb0ef41Sopenharmony_ciint init_gen_str(EVP_PKEY_CTX **pctx,
2831cb0ef41Sopenharmony_ci                 const char *algname, ENGINE *e, int do_param,
2841cb0ef41Sopenharmony_ci                 OSSL_LIB_CTX *libctx, const char *propq)
2851cb0ef41Sopenharmony_ci{
2861cb0ef41Sopenharmony_ci    EVP_PKEY_CTX *ctx = NULL;
2871cb0ef41Sopenharmony_ci    int pkey_id;
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_ci    if (*pctx) {
2901cb0ef41Sopenharmony_ci        BIO_puts(bio_err, "Algorithm already set!\n");
2911cb0ef41Sopenharmony_ci        return 0;
2921cb0ef41Sopenharmony_ci    }
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ci    pkey_id = get_legacy_pkey_id(libctx, algname, e);
2951cb0ef41Sopenharmony_ci    if (pkey_id != NID_undef)
2961cb0ef41Sopenharmony_ci        ctx = EVP_PKEY_CTX_new_id(pkey_id, e);
2971cb0ef41Sopenharmony_ci    else
2981cb0ef41Sopenharmony_ci        ctx = EVP_PKEY_CTX_new_from_name(libctx, algname, propq);
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_ci    if (ctx == NULL)
3011cb0ef41Sopenharmony_ci        goto err;
3021cb0ef41Sopenharmony_ci    if (do_param) {
3031cb0ef41Sopenharmony_ci        if (EVP_PKEY_paramgen_init(ctx) <= 0)
3041cb0ef41Sopenharmony_ci            goto err;
3051cb0ef41Sopenharmony_ci    } else {
3061cb0ef41Sopenharmony_ci        if (EVP_PKEY_keygen_init(ctx) <= 0)
3071cb0ef41Sopenharmony_ci            goto err;
3081cb0ef41Sopenharmony_ci    }
3091cb0ef41Sopenharmony_ci
3101cb0ef41Sopenharmony_ci    *pctx = ctx;
3111cb0ef41Sopenharmony_ci    return 1;
3121cb0ef41Sopenharmony_ci
3131cb0ef41Sopenharmony_ci err:
3141cb0ef41Sopenharmony_ci    BIO_printf(bio_err, "Error initializing %s context\n", algname);
3151cb0ef41Sopenharmony_ci    ERR_print_errors(bio_err);
3161cb0ef41Sopenharmony_ci    EVP_PKEY_CTX_free(ctx);
3171cb0ef41Sopenharmony_ci    return 0;
3181cb0ef41Sopenharmony_ci
3191cb0ef41Sopenharmony_ci}
3201cb0ef41Sopenharmony_ci
3211cb0ef41Sopenharmony_cistatic int genpkey_cb(EVP_PKEY_CTX *ctx)
3221cb0ef41Sopenharmony_ci{
3231cb0ef41Sopenharmony_ci    char c = '*';
3241cb0ef41Sopenharmony_ci    BIO *b = EVP_PKEY_CTX_get_app_data(ctx);
3251cb0ef41Sopenharmony_ci
3261cb0ef41Sopenharmony_ci    if (quiet)
3271cb0ef41Sopenharmony_ci        return 1;
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ci    switch (EVP_PKEY_CTX_get_keygen_info(ctx, 0)) {
3301cb0ef41Sopenharmony_ci    case 0:
3311cb0ef41Sopenharmony_ci        c = '.';
3321cb0ef41Sopenharmony_ci        break;
3331cb0ef41Sopenharmony_ci    case 1:
3341cb0ef41Sopenharmony_ci        c = '+';
3351cb0ef41Sopenharmony_ci        break;
3361cb0ef41Sopenharmony_ci    case 3:
3371cb0ef41Sopenharmony_ci        c = '\n';
3381cb0ef41Sopenharmony_ci        break;
3391cb0ef41Sopenharmony_ci    }
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_ci    BIO_write(b, &c, 1);
3421cb0ef41Sopenharmony_ci    (void)BIO_flush(b);
3431cb0ef41Sopenharmony_ci    return 1;
3441cb0ef41Sopenharmony_ci}
345