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