1 /*- 2 * Copyright 2021-2022 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 result = 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 result = 1; 126 cleanup: 127 /* Zeroize the private key data when we free it */ 128 BN_clear_free(out_priv); 129 return result; 130 } 131 132 int main(void) 133 { 134 int result = 0; 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 result = 1; 149 cleanup: 150 if (result != 1) 151 ERR_print_errors_fp(stderr); 152 153 EVP_PKEY_free(pkey); 154 return result == 0; 155 } 156