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