View Javadoc
1   /*
2    * Copyright (c) 2002-2026 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host.crypto;
16  
17  import java.util.Map;
18  import java.util.Set;
19  
20  import org.htmlunit.corejs.javascript.Scriptable;
21  import org.htmlunit.corejs.javascript.ScriptableObject;
22  import org.htmlunit.corejs.javascript.VarScope;
23  import org.htmlunit.javascript.JavaScriptEngine;
24  
25  /**
26   * Internal helper representing EC key algorithm parameters.
27   * Used by {@link SubtleCrypto} for ECDSA and ECDH key operations.
28   *
29   * @author Lai Quang Duong
30   * @author Ronald Brill
31   */
32  final class EcKeyAlgorithm {
33  
34      static final Set<String> SUPPORTED_NAMES = Set.of("ECDSA", "ECDH");
35  
36      private static final Map<String, String> CURVE_TO_JCA = Map.of(
37              "P-256", "secp256r1",
38              "P-384", "secp384r1",
39              "P-521", "secp521r1"
40      );
41  
42      private final String name_;
43      private final String namedCurve_;
44  
45      EcKeyAlgorithm(final String name, final String namedCurve) {
46          if (!SUPPORTED_NAMES.contains(name)) {
47              throw new UnsupportedOperationException("EC " + name);
48          }
49          name_ = name;
50  
51          if (!CURVE_TO_JCA.containsKey(namedCurve)) {
52              throw new UnsupportedOperationException("EC curve " + namedCurve);
53          }
54          namedCurve_ = namedCurve;
55      }
56  
57      /**
58       * Parse EC key algorithm parameters from a JS object.
59       *
60       * @param keyGenParams the JS algorithm parameters object
61       * @return the parsed EcKeyAlgorithm
62       */
63      static EcKeyAlgorithm from(final Scriptable keyGenParams) {
64          final Object nameProp = ScriptableObject.getProperty(keyGenParams, "name");
65          if (!(nameProp instanceof String name)) {
66              throw new IllegalArgumentException("An invalid or illegal string was specified");
67          }
68  
69          final Object curveProp = ScriptableObject.getProperty(keyGenParams, "namedCurve");
70          if (!(curveProp instanceof String namedCurve)) {
71              throw new IllegalArgumentException("An invalid or illegal string was specified");
72          }
73  
74          return new EcKeyAlgorithm(name, namedCurve);
75      }
76  
77      static boolean isSupported(final String name) {
78          return SUPPORTED_NAMES.contains(name);
79      }
80  
81      String getName() {
82          return name_;
83      }
84  
85      String getNamedCurve() {
86          return namedCurve_;
87      }
88  
89      /**
90       * @return the JCA curve name (e.g. "secp256r1" for "P-256")
91       */
92      String getJavaCurveName() {
93          return CURVE_TO_JCA.get(namedCurve_);
94      }
95  
96      /**
97       * Converts to a JS object matching the {@code EcKeyAlgorithm} dictionary:
98       * {@code {name: "ECDSA", namedCurve: "P-256"}}
99       *
100      * @param scope the JS scope for prototype/parent setup
101      * @return the JS algorithm object
102      */
103     Scriptable toScriptableObject(final VarScope scope) {
104         final Scriptable algorithm = JavaScriptEngine.newObject(scope);
105         ScriptableObject.putProperty(algorithm, "name", getName());
106         ScriptableObject.putProperty(algorithm, "namedCurve", getNamedCurve());
107         return algorithm;
108     }
109 }