Commit 4ef7e3b3cd for openssl.org

commit 4ef7e3b3cdc483cebb55b240770a2ee6e705b8db
Author: Jakub Zelenka <jakub.zelenka@openssl.foundation>
Date:   Tue Jul 14 19:01:24 2026 +0200

    apps: test ec and ecparam -text options

    The -text option was not exercised for the ec or ecparam apps. Add a
    subtest to 15-test_ec.t that prints a private and a public EC key and,
    after stripping the colon-separated hex formatting, verifies the printed
    private and public values match the committed testec-p256.pem keypair as
    well as the curve identification. Add a subtest to 15-test_ecparam.t
    that prints named and explicit parameters, checking the named form emits
    the expected curve OID and NIST name while the explicit form emits the
    field parameters and no OID.

    Assisted-by: Claude:claude-opus-4-8

    Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
    Reviewed-by: Daniel Kubec <kubec@openssl.foundation>
    Reviewed-by: Tim Hudson <tjh@openssl.org>
    MergeDate: Fri Jul 17 08:47:12 2026
    (Merged from https://github.com/openssl/openssl/pull/31952)

diff --git a/test/recipes/15-test_ec.t b/test/recipes/15-test_ec.t
index 5b0a69f0ca..e3d18a8849 100644
--- a/test/recipes/15-test_ec.t
+++ b/test/recipes/15-test_ec.t
@@ -19,7 +19,7 @@ setup("test_ec");

 plan skip_all => 'EC is not supported in this build' if disabled('ec');

-plan tests => 18;
+plan tests => 19;

 my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0);

@@ -152,6 +152,55 @@ subtest 'EC parameter encoding (-param_enc)' => sub {
        "an invalid parameter encoding is rejected");
 };

+subtest 'ec -text prints the key in text form' => sub {
+    plan tests => 7;
+
+    my $priv_key = srctop_file("test", "testec-p256.pem");
+    my $pub_key = srctop_file("test", "testecpub-p256.pem");
+
+    # The private (priv) and public (pub) values of the committed
+    # testec-p256.pem / testecpub-p256.pem keypair.  -text prints them as
+    # colon-separated hex; we strip the formatting and compare against the
+    # known values so the actual key material, not just the labels, is checked.
+    my $priv_hex = "36045F6C909612570C8C0113071FC809F6788084289C6AB003C60A"
+        . "17B2D5ADAD";
+    my $pub_hex = "04257C007484E23C571252C6912369E5CD33519FEFAAE85DFC5EB1FC"
+        . "9BCB1FDBC0D0FB63A86F9494CEF823552D1EEF4A48A87E9B4970E03DCF262AD"
+        . "4ACF598B6E9";
+
+    # ec -text on the private key.
+    my @priv = run(app(['openssl', 'ec', '-text', '-noout', '-in', $priv_key],
+                       stderr => undef),
+                   capture => 1);
+    chomp @priv;
+    my $priv_blob = uc join('', @priv);
+    $priv_blob =~ s/[^0-9A-F]//g;
+    ok(grep(/^Private-Key: \(256 bit field, 128 bit security level\)$/, @priv),
+       "ec -text prints the private key header");
+    ok(index($priv_blob, $priv_hex) >= 0,
+       "ec -text prints the expected private value");
+    ok(index($priv_blob, $pub_hex) >= 0,
+       "ec -text prints the expected public value");
+    ok(grep(/^ASN1 OID: prime256v1$/, @priv)
+       && grep(/^NIST CURVE: P-256$/, @priv),
+       "ec -text prints the curve identification");
+
+    # ec -text on the public key.
+    my @pub = run(app(['openssl', 'ec', '-pubin', '-text', '-noout',
+                       '-in', $pub_key],
+                      stderr => undef),
+                  capture => 1);
+    chomp @pub;
+    my $pub_blob = uc join('', @pub);
+    $pub_blob =~ s/[^0-9A-F]//g;
+    ok(grep(/^Public-Key: \(256 bit field, 128 bit security level\)$/, @pub),
+       "ec -text prints the public key header");
+    ok(index($pub_blob, $pub_hex) >= 0,
+       "ec -text prints the expected public value for a public key");
+    ok(!grep(/^priv:/, @pub),
+       "ec -text does not print a private component for a public key");
+};
+
 subtest 'Check loading of fips and non-fips keys' => sub {
     plan skip_all => "FIPS is disabled"
         if $no_fips;
diff --git a/test/recipes/15-test_ecparam.t b/test/recipes/15-test_ecparam.t
index 571c62cf1a..169814b4e5 100644
--- a/test/recipes/15-test_ecparam.t
+++ b/test/recipes/15-test_ecparam.t
@@ -30,7 +30,7 @@ if (disabled("sm2")) {
     @valid = grep { !/sm2-.*\.pem/} @valid;
 }

-plan tests => 15;
+plan tests => 16;

 sub checkload {
     my $files = shift; # List of files
@@ -224,4 +224,37 @@ subtest "Check ecparam -param_enc converts between named and explicit" => sub {
        "an invalid parameter encoding is rejected");
 };

+subtest "Check ecparam -text prints the parameters in text form" => sub {
+    plan tests => 6;
+
+    my $named = data_file('valid', 'secp384r1-named.pem');
+    my $explicit = data_file('valid', 'secp384r1-explicit.pem');
+
+    # Named parameters print the curve identification.
+    my @named = run(app(['openssl', 'ecparam', '-text', '-noout', '-in', $named],
+                        stderr => undef),
+                    capture => 1);
+    chomp @named;
+    ok(grep(/^EC-Parameters: \(384 bit field, 192 bit security level\)$/, @named),
+       "named parameters print the EC-Parameters header");
+    ok(grep(/^ASN1 OID: secp384r1$/, @named),
+       "named parameters print the expected curve OID");
+    ok(grep(/^NIST CURVE: P-384$/, @named),
+       "named parameters print the expected NIST curve name");
+
+    # Explicit parameters print the field parameters instead of the curve name.
+    my @explicit = run(app(['openssl', 'ecparam', '-text', '-noout',
+                            '-in', $explicit],
+                           stderr => undef),
+                       capture => 1);
+    chomp @explicit;
+    ok(grep(/^EC-Parameters: \(384 bit field, 192 bit security level\)$/, @explicit),
+       "explicit parameters print the EC-Parameters header");
+    ok(grep(/^Field Type: prime-field$/, @explicit)
+       && grep(/^Cofactor:/, @explicit),
+       "explicit parameters print the field parameters");
+    ok(!grep(/^ASN1 OID:/, @explicit),
+       "explicit parameters do not print a curve OID");
+};
+
 ok(run(app(['openssl', 'ecparam', '-list_curves'])), "Test -list_curves");