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