Commit 9d036bdd8f for openssl.org

commit 9d036bdd8fb794363feb2f3e02dacd675b497935
Author: Pauli <paul.dale@oracle.com>
Date:   Fri Sep 4 10:22:41 2026 +1000

    params: add directive for dealing with duplicated parameters

    The generated param name decoders will, by default, return an error
    if a duplicate param name is encountered. Although passing a repeated
    parameter is a bug in the caller, this isn't always desirable behaviour.

    Add the ability to accept the first occupance and to ignore later ones.

    Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
    Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
    Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
    Merge-date: Mon Sep  7 18:14:54 2026
    Merged-from: https://github.com/openssl/openssl/pull/32675

diff --git a/util/perl/OpenSSL/paramnames.pm b/util/perl/OpenSSL/paramnames.pm
index dd34cee7d8..9e97187c52 100644
--- a/util/perl/OpenSSL/paramnames.pm
+++ b/util/perl/OpenSSL/paramnames.pm
@@ -704,6 +704,7 @@ sub trie_matched {
   my $with_count = shift;
   my $field = shift;
   my $num = shift;
+  my $dup = shift;
   my $indent1 = shift;
   my $indent2 = shift;

@@ -721,9 +722,13 @@ sub trie_matched {
     printf "%sr->%s[r->num_%s++] = (OSSL_PARAM *)p;\n", $indent1, $field, $field;
   } else {
     printf "%sif (ossl_unlikely(r->%s != NULL)) {\n", $indent1, $field;
-    printf "%sERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,\n", $indent2;
-    printf "%s               \"param %%s is repeated\", s);\n", $indent2;
-    printf "%sreturn 0;\n", $indent2;
+    if (defined $dup && $dup eq 'first') {
+      printf "%sbreak;\n", $indent2;
+    } else {
+      printf "%sERR_raise_data(ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER,\n", $indent2;
+      printf "%s               \"param %%s is repeated\", s);\n", $indent2;
+      printf "%sreturn 0;\n", $indent2;
+    }
     printf "%s}\n", $indent1;
     printf "%s++*count;\n", $indent1 if $with_count;
     printf "%sr->%s = (OSSL_PARAM *)p;\n", $indent1, $field;
@@ -736,6 +741,7 @@ sub generate_decoder_from_trie {
     my $trieref = shift;
     my $identmap = shift;
     my $concat_num = shift;
+    my $process_dup = shift;
     my $ifdefs = shift;
     my $idt = "    ";
     my $indent0 = $idt x ($n + 3);
@@ -749,6 +755,7 @@ sub generate_decoder_from_trie {

         $field = $identmap->{$trieref->{'name'}};
         my $num = $concat_num->{$field};
+        my $dup = $process_dup->{$field};
         output_ifdef($ifdefs->{$field});
         printf "%sif (ossl_likely($strcmp(\"$suf\", s + $n) == 0", $indent0;
         if (not $case_sensitive) {
@@ -758,7 +765,7 @@ sub generate_decoder_from_trie {
         }
         print ")) {\n";
         printf "%s/* %s */\n", $indent1, $trieref->{'name'};
-        trie_matched($with_count, $field, $num, $indent1, $indent2);
+        trie_matched($with_count, $field, $num, $dup, $indent1, $indent2);
         printf "%s}\n", $indent0;

         # If this is at the top level and it's conditional, we have to
@@ -777,10 +784,11 @@ sub generate_decoder_from_trie {
         if ($l eq 'val') {
             $field = $identmap->{$trieref->{'val'}};
             my $num = $concat_num->{$field};
+            my $dup = $process_dup->{$field};
             printf "%sbreak;\n", $indent1;
             printf "%scase '\\0':\n", $indent0;
             output_ifdef($ifdefs->{$field});
-            trie_matched($with_count, $field, $num, $indent1, $indent2);
+            trie_matched($with_count, $field, $num, $dup, $indent1, $indent2);
             output_endifdef($ifdefs->{$field});
         } else {
             printf "%sbreak;\n", $indent1;
@@ -790,7 +798,7 @@ sub generate_decoder_from_trie {
                 printf "   case '%s':", uc $l if ($l =~ /[a-z]/);
             }
             print "\n";
-            generate_decoder_from_trie($with_count, $n + 1, $trieref->{$l}, $identmap, $concat_num, $ifdefs);
+            generate_decoder_from_trie($with_count, $n + 1, $trieref->{$l}, $identmap, $concat_num, $process_dup, $ifdefs);
         }
     }
     if ($need_break) {
@@ -867,6 +875,7 @@ sub output_param_decoder {
     my @keys = ();
     my %prms = ();
     my %concat_num = ();
+    my %process_dup = ();
     my %ifdefs = ();

     if (!$headers_included) {
@@ -907,6 +916,10 @@ sub output_param_decoder {
             } elsif (substr($pnum, 0, 3) eq '#if') {
                 # Trim the `#if' from the front
                 $ifdefs{$pident} = substr($pnum, 3);
+            } elsif ($pnum =~ '^duplicate: *(first)') {
+                # This provides a provision for other duplicate resolution methods
+                # even though they aren't implemented yet
+                $process_dup{$pident} = $1;
             } elsif (not defined $concat_num{$pident}) {
                 $concat_num{$pident} = $pnum;
             }
@@ -963,7 +976,7 @@ sub output_param_decoder {
     print "    memset(r, 0, sizeof(*r));\n";
     print "    if (p != NULL)\n";
     print "        for (; (s = p->key) != NULL; p++)\n";
-    generate_decoder_from_trie($with_count, 0, \%t, \%prms, \%concat_num, \%ifdefs);
+    generate_decoder_from_trie($with_count, 0, \%t, \%prms, \%concat_num, \%process_dup, \%ifdefs);
     print "    return 1;\n";
     print "}\n#endif\n";
     print "/* End of machine generated */";