Home | History | Annotate | Line # | Download | only in pkey
      1 /*-
      2  * Copyright 2021-2023 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 /*
     11  * Example showing how to generate an EC key and extract values from the
     12  * generated key.
     13  */
     14 
     15 #include <string.h>
     16 #include <stdio.h>
     17 #include <openssl/err.h>
     18 #include <openssl/evp.h>
     19 #include <openssl/core_names.h>
     20 
     21 static int get_key_values(EVP_PKEY *pkey);
     22 
     23 /*
     24  * The following code shows how to generate an EC key from a curve name
     25  * with additional parameters. If only the curve name is required then the
     26  * simple helper can be used instead i.e. Either
     27  * pkey = EVP_EC_gen(curvename); OR
     28  * pkey = EVP_PKEY_Q_keygen(libctx, propq, "EC", curvename);
     29  */
     30 static EVP_PKEY *do_ec_keygen(void)
     31 {
     32     /*
     33      * The libctx and propq can be set if required, they are included here
     34      * to show how they are passed to EVP_PKEY_CTX_new_from_name().
     35      */
     36     OSSL_LIB_CTX *libctx = NULL;
     37     const char *propq = NULL;
     38     EVP_PKEY *key = NULL;
     39     OSSL_PARAM params[3];
     40     EVP_PKEY_CTX *genctx = NULL;
     41     const char *curvename = "P-256";
     42     int use_cofactordh = 1;
     43 
     44     genctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", propq);
     45     if (genctx == NULL) {
     46         fprintf(stderr, "EVP_PKEY_CTX_new_from_name() failed\n");
     47         goto cleanup;
     48     }
     49 
     50     if (EVP_PKEY_keygen_init(genctx) <= 0) {
     51         fprintf(stderr, "EVP_PKEY_keygen_init() failed\n");
     52         goto cleanup;
     53     }
     54 
     55     params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
     56         (char *)curvename, 0);
     57     /*
     58      * This is an optional parameter.
     59      * For many curves where the cofactor is 1, setting this has no effect.
     60      */
     61     params[1] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_USE_COFACTOR_ECDH,
     62         &use_cofactordh);
     63     params[2] = OSSL_PARAM_construct_end();
     64     if (!EVP_PKEY_CTX_set_params(genctx, params)) {
     65         fprintf(stderr, "EVP_PKEY_CTX_set_params() failed\n");
     66         goto cleanup;
     67     }
     68 
     69     fprintf(stdout, "Generating EC key\n\n");
     70     if (EVP_PKEY_generate(genctx, &key) <= 0) {
     71         fprintf(stderr, "EVP_PKEY_generate() failed\n");
     72         goto cleanup;
     73     }
     74 cleanup:
     75     EVP_PKEY_CTX_free(genctx);
     76     return key;
     77 }
     78 
     79 /*
     80  * The following code shows how retrieve key data from the generated
     81  * EC key. See doc/man7/EVP_PKEY-EC.pod for more information.
     82  *
     83  * EVP_PKEY_print_private() could also be used to display the values.
     84  */
     85 static int get_key_values(EVP_PKEY *pkey)
     86 {
     87     int ret = 0;
     88     char out_curvename[80];
     89     unsigned char out_pubkey[80];
     90     unsigned char out_privkey[80];
     91     BIGNUM *out_priv = NULL;
     92     size_t out_pubkey_len, out_privkey_len = 0;
     93 
     94     if (!EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME,
     95             out_curvename, sizeof(out_curvename),
     96             NULL)) {
     97         fprintf(stderr, "Failed to get curve name\n");
     98         goto cleanup;
     99     }
    100 
    101     if (!EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY,
    102             out_pubkey, sizeof(out_pubkey),
    103             &out_pubkey_len)) {
    104         fprintf(stderr, "Failed to get public key\n");
    105         goto cleanup;
    106     }
    107 
    108     if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &out_priv)) {
    109         fprintf(stderr, "Failed to get private key\n");
    110         goto cleanup;
    111     }
    112 
    113     out_privkey_len = BN_bn2bin(out_priv, out_privkey);
    114     if (out_privkey_len <= 0 || out_privkey_len > sizeof(out_privkey)) {
    115         fprintf(stderr, "BN_bn2bin failed\n");
    116         goto cleanup;
    117     }
    118 
    119     fprintf(stdout, "Curve name: %s\n", out_curvename);
    120     fprintf(stdout, "Public key:\n");
    121     BIO_dump_indent_fp(stdout, out_pubkey, out_pubkey_len, 2);
    122     fprintf(stdout, "Private Key:\n");
    123     BIO_dump_indent_fp(stdout, out_privkey, out_privkey_len, 2);
    124 
    125     ret = 1;
    126 cleanup:
    127     /* Zeroize the private key data when we free it */
    128     BN_clear_free(out_priv);
    129     return ret;
    130 }
    131 
    132 int main(void)
    133 {
    134     int ret = EXIT_FAILURE;
    135     EVP_PKEY *pkey;
    136 
    137     pkey = do_ec_keygen();
    138     if (pkey == NULL)
    139         goto cleanup;
    140 
    141     if (!get_key_values(pkey))
    142         goto cleanup;
    143 
    144     /*
    145      * At this point we can write out the generated key using
    146      * i2d_PrivateKey() and i2d_PublicKey() if required.
    147      */
    148     ret = EXIT_SUCCESS;
    149 cleanup:
    150     if (ret != EXIT_SUCCESS)
    151         ERR_print_errors_fp(stderr);
    152 
    153     EVP_PKEY_free(pkey);
    154     return ret;
    155 }
    156