Update copyright year
[openssl.git] / apps / ec.c
index 9cf6e1a545427edc7046fe1b067cf5ff25c3845d..fe9a774ab4d524f96655f2d4b4326efcb454471f 100644 (file)
--- a/apps/ec.c
+++ b/apps/ec.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2002-2022 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -7,33 +7,22 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <string.h>
 #include <openssl/opensslconf.h>
+#include <openssl/evp.h>
+#include <openssl/encoder.h>
+#include <openssl/decoder.h>
+#include <openssl/core_names.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/params.h>
+#include <openssl/err.h>
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 #include "apps.h"
 #include "progs.h"
-#include <openssl/bio.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-
-static OPT_PAIR conv_forms[] = {
-    {"compressed", POINT_CONVERSION_COMPRESSED},
-    {"uncompressed", POINT_CONVERSION_UNCOMPRESSED},
-    {"hybrid", POINT_CONVERSION_HYBRID},
-    {NULL}
-};
-
-static OPT_PAIR param_enc[] = {
-    {"named_curve", OPENSSL_EC_NAMED_CURVE},
-    {"explicit", 0},
-    {NULL}
-};
+#include "ec_common.h"
 
 typedef enum OPTION_choice {
-    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
+    OPT_COMMON,
     OPT_INFORM, OPT_OUTFORM, OPT_ENGINE, OPT_IN, OPT_OUT,
     OPT_NOOUT, OPT_TEXT, OPT_PARAM_OUT, OPT_PUBIN, OPT_PUBOUT,
     OPT_PASSIN, OPT_PASSOUT, OPT_PARAM_ENC, OPT_CONV_FORM, OPT_CIPHER,
@@ -49,7 +38,7 @@ const OPTIONS ec_options[] = {
 
     OPT_SECTION("Input"),
     {"in", OPT_IN, 's', "Input file"},
-    {"inform", OPT_INFORM, 'f', "Input format - DER or PEM"},
+    {"inform", OPT_INFORM, 'f', "Input format (DER/PEM/P12/ENGINE)"},
     {"pubin", OPT_PUBIN, '-', "Expect a public key in input file"},
     {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
     {"check", OPT_CHECK, '-', "check key consistency"},
@@ -74,20 +63,24 @@ const OPTIONS ec_options[] = {
 
 int ec_main(int argc, char **argv)
 {
-    BIO *in = NULL, *out = NULL;
+    OSSL_ENCODER_CTX *ectx = NULL;
+    OSSL_DECODER_CTX *dctx = NULL;
+    EVP_PKEY_CTX *pctx = NULL;
+    EVP_PKEY *eckey = NULL;
+    BIO *out = NULL;
     ENGINE *e = NULL;
-    EC_KEY *eckey = NULL;
-    const EC_GROUP *group;
-    const EVP_CIPHER *enc = NULL;
-    point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED;
-    char *infile = NULL, *outfile = NULL, *prog;
+    EVP_CIPHER *enc = NULL;
+    char *infile = NULL, *outfile = NULL, *ciphername = NULL, *prog;
     char *passin = NULL, *passout = NULL, *passinarg = NULL, *passoutarg = NULL;
     OPTION_CHOICE o;
-    int asn1_flag = OPENSSL_EC_NAMED_CURVE, new_form = 0, new_asn1_flag = 0;
-    int informat = FORMAT_PEM, outformat = FORMAT_PEM, text = 0, noout = 0;
-    int pubin = 0, pubout = 0, param_out = 0, i, ret = 1, private = 0;
-    int no_public = 0, check = 0;
+    int informat = FORMAT_UNDEF, outformat = FORMAT_PEM, text = 0, noout = 0;
+    int pubin = 0, pubout = 0, param_out = 0, ret = 1, private = 0;
+    int check = 0;
+    char *asn1_encoding = NULL;
+    char *point_format = NULL;
+    int no_public = 0;
 
+    opt_set_unknown_name("cipher");
     prog = opt_init(argc, argv, ec_options);
     while ((o = opt_next()) != OPT_EOF) {
         switch (o) {
@@ -139,20 +132,17 @@ int ec_main(int argc, char **argv)
             e = setup_engine(opt_arg(), 0);
             break;
         case OPT_CIPHER:
-            if (!opt_cipher(opt_unknown(), &enc))
-                goto opthelp;
+            ciphername = opt_unknown();
             break;
         case OPT_CONV_FORM:
-            if (!opt_pair(opt_arg(), conv_forms, &i))
+            point_format = opt_arg();
+            if (!opt_string(point_format, point_format_options))
                 goto opthelp;
-            new_form = 1;
-            form = i;
             break;
         case OPT_PARAM_ENC:
-            if (!opt_pair(opt_arg(), param_enc, &i))
+            asn1_encoding = opt_arg();
+            if (!opt_string(asn1_encoding, asn1_encoding_options))
                 goto opthelp;
-            new_asn1_flag = 1;
-            asn1_flag = i;
             break;
         case OPT_NO_PUBLIC:
             no_public = 1;
@@ -166,10 +156,13 @@ int ec_main(int argc, char **argv)
             break;
         }
     }
-    argc = opt_num_rest();
-    if (argc != 0)
+
+    /* No extra arguments. */
+    if (!opt_check_rest_arg(NULL))
         goto opthelp;
 
+    if (!opt_cipher(ciphername, &enc))
+        goto opthelp;
     private = param_out || pubin || pubout ? 0 : 1;
     if (text && !pubin)
         private = 1;
@@ -179,37 +172,15 @@ int ec_main(int argc, char **argv)
         goto end;
     }
 
-    if (informat != FORMAT_ENGINE) {
-        in = bio_open_default(infile, 'r', informat);
-        if (in == NULL)
-            goto end;
-    }
-
     BIO_printf(bio_err, "read EC key\n");
-    if (informat == FORMAT_ASN1) {
-        if (pubin)
-            eckey = d2i_EC_PUBKEY_bio(in, NULL);
-        else
-            eckey = d2i_ECPrivateKey_bio(in, NULL);
-    } else if (informat == FORMAT_ENGINE) {
-        EVP_PKEY *pkey;
-        if (pubin)
-            pkey = load_pubkey(infile, informat, 1, passin, e, "Public Key");
-        else
-            pkey = load_key(infile, informat, 1, passin, e, "Private Key");
-        if (pkey != NULL) {
-            eckey = EVP_PKEY_get1_EC_KEY(pkey);
-            EVP_PKEY_free(pkey);
-        }
-    } else {
-        if (pubin)
-            eckey = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, NULL);
-        else
-            eckey = PEM_read_bio_ECPrivateKey(in, NULL, NULL, passin);
-    }
+
+    if (pubin)
+        eckey = load_pubkey(infile, informat, 1, passin, e, "public key");
+    else
+        eckey = load_key(infile, informat, 1, passin, e, "private key");
+
     if (eckey == NULL) {
         BIO_printf(bio_err, "unable to load Key\n");
-        ERR_print_errors(bio_err);
         goto end;
     }
 
@@ -217,74 +188,105 @@ int ec_main(int argc, char **argv)
     if (out == NULL)
         goto end;
 
-    group = EC_KEY_get0_group(eckey);
-
-    if (new_form)
-        EC_KEY_set_conv_form(eckey, form);
+    if (point_format
+        && !EVP_PKEY_set_utf8_string_param(
+                eckey, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
+                point_format)) {
+        BIO_printf(bio_err, "unable to set point conversion format\n");
+        goto end;
+    }
 
-    if (new_asn1_flag)
-        EC_KEY_set_asn1_flag(eckey, asn1_flag);
+    if (asn1_encoding != NULL
+        && !EVP_PKEY_set_utf8_string_param(
+                eckey, OSSL_PKEY_PARAM_EC_ENCODING, asn1_encoding)) {
+        BIO_printf(bio_err, "unable to set asn1 encoding format\n");
+        goto end;
+    }
 
-    if (no_public)
-        EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
+    if (no_public) {
+        if (!EVP_PKEY_set_int_param(eckey, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 0)) {
+            BIO_printf(bio_err, "unable to disable public key encoding\n");
+            goto end;
+        }
+    } else {
+        if (!EVP_PKEY_set_int_param(eckey, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, 1)) {
+            BIO_printf(bio_err, "unable to enable public key encoding\n");
+            goto end;
+        }
+    }
 
     if (text) {
         assert(pubin || private);
-        if (!EC_KEY_print(out, eckey, 0)) {
-            perror(outfile);
-            ERR_print_errors(bio_err);
+        if ((pubin && EVP_PKEY_print_public(out, eckey, 0, NULL) <= 0)
+            || (!pubin && EVP_PKEY_print_private(out, eckey, 0, NULL) <= 0)) {
+            BIO_printf(bio_err, "unable to print EC key\n");
             goto end;
         }
     }
 
     if (check) {
-        if (EC_KEY_check_key(eckey) == 1) {
-            BIO_printf(bio_err, "EC Key valid.\n");
-        } else {
-            BIO_printf(bio_err, "EC Key Invalid!\n");
-            ERR_print_errors(bio_err);
+        pctx = EVP_PKEY_CTX_new_from_pkey(NULL, eckey, NULL);
+        if (pctx == NULL) {
+            BIO_printf(bio_err, "unable to check EC key\n");
+            goto end;
         }
+        if (!EVP_PKEY_check(pctx))
+            BIO_printf(bio_err, "EC Key Invalid!\n");
+        else
+            BIO_printf(bio_err, "EC Key valid.\n");
+        ERR_print_errors(bio_err);
     }
 
-    if (noout) {
-        ret = 0;
-        goto end;
-    }
+    if (!noout) {
+        int selection;
+        const char *output_type = outformat == FORMAT_ASN1 ? "DER" : "PEM";
+        const char *output_structure = "type-specific";
 
-    BIO_printf(bio_err, "writing EC key\n");
-    if (outformat == FORMAT_ASN1) {
+        BIO_printf(bio_err, "writing EC key\n");
         if (param_out) {
-            i = i2d_ECPKParameters_bio(out, group);
+            selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS;
         } else if (pubin || pubout) {
-            i = i2d_EC_PUBKEY_bio(out, eckey);
+            selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS
+                | OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
+            output_structure = "SubjectPublicKeyInfo";
         } else {
+            selection = OSSL_KEYMGMT_SELECT_ALL;
             assert(private);
-            i = i2d_ECPrivateKey_bio(out, eckey);
         }
-    } else {
-        if (param_out) {
-            i = PEM_write_bio_ECPKParameters(out, group);
-        } else if (pubin || pubout) {
-            i = PEM_write_bio_EC_PUBKEY(out, eckey);
-        } else {
-            assert(private);
-            i = PEM_write_bio_ECPrivateKey(out, eckey, enc,
-                                           NULL, 0, NULL, passout);
+
+        ectx = OSSL_ENCODER_CTX_new_for_pkey(eckey, selection,
+                                             output_type, output_structure,
+                                             NULL);
+        if (enc != NULL) {
+            OSSL_ENCODER_CTX_set_cipher(ectx, EVP_CIPHER_get0_name(enc), NULL);
+            /* Default passphrase prompter */
+            OSSL_ENCODER_CTX_set_passphrase_ui(ectx, get_ui_method(), NULL);
+            if (passout != NULL)
+                /* When passout given, override the passphrase prompter */
+                OSSL_ENCODER_CTX_set_passphrase(ectx,
+                                                (const unsigned char *)passout,
+                                                strlen(passout));
+        }
+        if (!OSSL_ENCODER_to_bio(ectx, out)) {
+            BIO_printf(bio_err, "unable to write EC key\n");
+            goto end;
         }
     }
 
-    if (!i) {
-        BIO_printf(bio_err, "unable to write private key\n");
+    ret = 0;
+end:
+    if (ret != 0)
         ERR_print_errors(bio_err);
-    } else {
-        ret = 0;
-    }
- end:
-    BIO_free(in);
     BIO_free_all(out);
-    EC_KEY_free(eckey);
+    EVP_PKEY_free(eckey);
+    EVP_CIPHER_free(enc);
+    OSSL_ENCODER_CTX_free(ectx);
+    OSSL_DECODER_CTX_free(dctx);
+    EVP_PKEY_CTX_free(pctx);
     release_engine(e);
-    OPENSSL_free(passin);
-    OPENSSL_free(passout);
+    if (passin != NULL)
+        OPENSSL_clear_free(passin, strlen(passin));
+    if (passout != NULL)
+        OPENSSL_clear_free(passout, strlen(passout));
     return ret;
 }