001    // Copyright (C) 2002 IAIK
002    // https://jce.iaik.tugraz.at
003    //
004    // Copyright (C) 2003 - 2025 Stiftung Secure Information and
005    //                           Communication Technologies SIC
006    // https://sic.tech
007    //
008    // All rights reserved.
009    //
010    // Redistribution and use in source and binary forms, with or without
011    // modification, are permitted provided that the following conditions
012    // are met:
013    // 1. Redistributions of source code must retain the above copyright
014    //    notice, this list of conditions and the following disclaimer.
015    // 2. Redistributions in binary form must reproduce the above copyright
016    //    notice, this list of conditions and the following disclaimer in the
017    //    documentation and/or other materials provided with the distribution.
018    //
019    // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
020    // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
021    // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
022    // ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
023    // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
024    // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
025    // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
026    // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
027    // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
028    // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
029    // SUCH DAMAGE.
030    
031    // Copyright (C) 2002 IAIK
032    // https://sic.tech
033    //
034    // Copyright (C) 2003 - 2025 Stiftung Secure Information and
035    //                           Communication Technologies SIC
036    // https://sic.tech
037    //
038    // All rights reserved.
039    //
040    // This source is provided for inspection purposes and recompilation only,
041    // unless specified differently in a contract with IAIK. This source has to
042    // be kept in strict confidence and must not be disclosed to any third party
043    // under any circumstances. Redistribution in source and binary forms, with
044    // or without modification, are <not> permitted in any case!
045    //
046    // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
047    // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
048    // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
049    // ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
050    // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
051    // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
052    // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
053    // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
054    // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
055    // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
056    // SUCH DAMAGE.
057    //
058    // $Header: /IAIK-CMS/current/src/demo/cms/ecc/ECCDemoUtil.java 18    12.02.25 17:58 Dbratko $
059    // $Revision: 18 $
060    
061    package demo.cms.ecc;
062    
063    
064    
065    import java.lang.reflect.Constructor;
066    import java.lang.reflect.Field;
067    import java.lang.reflect.Method;
068    import java.security.InvalidAlgorithmParameterException;
069    import java.security.InvalidKeyException;
070    import java.security.NoSuchAlgorithmException;
071    import java.security.NoSuchProviderException;
072    import java.security.PrivateKey;
073    import java.security.Provider;
074    import java.security.Security;
075    import java.security.cert.CertificateException;
076    import java.security.spec.AlgorithmParameterSpec;
077    import java.security.spec.InvalidParameterSpecException;
078    
079    import iaik.asn1.structures.AlgorithmID;
080    import iaik.cms.IaikProvider;
081    import iaik.cms.SecurityProvider;
082    import iaik.cms.Utils;
083    import iaik.x509.X509Certificate;
084    
085    /**
086     * Some utilities for the ECC demos.
087     */
088    public class ECCDemoUtil {
089      
090      /**
091       * ECC supporting CMS SecurityProvider.
092       */
093      private static IaikProvider iaikEccProvider_;
094      
095      /**
096       * Version of the IAIK ECCelerate provider; if used.
097       */
098      private static Double eccelerateVersion_ = null;
099      
100      
101      /**
102       * Installs an ECC supporting IAIK SecurityProvider. Depending on its presence in
103       * the classpath, either the new (ECCelerate) or old (IAIK-ECC) library is used.
104       * 
105       * @return the ECC supporting IAIK SecurityProvider
106       * 
107       * @throws Exception if the IAIK ECC Provider cannot be installed
108       */
109      public static IaikProvider installIaikEccProvider() throws Exception {
110        if (iaikEccProvider_ == null) { 
111          IaikProvider iaikEccProvider = null;
112          
113          try {
114            iaikEccProvider = installIaikEccelerateProvider();
115          } catch (Throwable t) {
116            // ignore; try old IAIK-ECC library
117          }  
118         
119          if (iaikEccProvider == null) {
120            if (Utils.isClassAvailable("iaik.security.ecc.provider.ECCProvider")) {
121              // old IAIK-ECC library   
122              iaikEccProvider = (IaikProvider)Class.forName("iaik.cms.ecc.IaikEccProvider").newInstance();
123              
124              try {
125                // set default domain parameter encoding as OID
126                Class ecdsaParameterCl = null;
127                ecdsaParameterCl = Class.forName("iaik.security.ecc.ecdsa.ECDSAParameter");
128                Method method = ecdsaParameterCl.getDeclaredMethod("setDefaultOIDEncoding", new Class[] {boolean.class});
129                method.invoke(ecdsaParameterCl, new Object[] { Boolean.TRUE });
130              } catch (Throwable t) {
131                System.out.println("Warning: could not set oid as default demoan parameter encoding for IAIK_ECC: " + t.toString());
132              }
133            }
134          }  
135          if (iaikEccProvider == null) {
136            throw new Exception("Cannot install ECC SecurityProvider!");
137          }
138          iaikEccProvider_ = iaikEccProvider;
139        }  
140        SecurityProvider.setSecurityProvider(iaikEccProvider_);
141        return iaikEccProvider_;
142      }
143      
144      /**
145       * Installs the IAIK ECCelerate SecurityProvider.
146       * 
147       * @return the IAIK ECCelerate SecurityProvider
148       * 
149       * @throws Exception if the provider cannot be installed
150       */
151      public static IaikProvider installIaikEccelerateProvider() throws Exception {
152        if ((iaikEccProvider_ == null) || 
153            (!"iaik.cms.ecc.ECCelerateProvider".equals(iaikEccProvider_.getClass().getName()))) { 
154          IaikProvider iaikEccProvider = null;
155          Class eccelerateProviderCl = null;
156          try {
157            eccelerateProviderCl = Class.forName("iaik.security.ec.provider.ECCelerate");
158          } catch (Throwable t) {
159            throw new NoSuchProviderException("Ecclerate provider not available: " + t.toString());
160          }  
161         
162          // new IAIK-ECC library
163          Provider eccProvider = (Provider)eccelerateProviderCl.newInstance();
164          Class iaikCmsEccelerateProviderCl = null;
165          try {
166            iaikCmsEccelerateProviderCl = Class.forName("iaik.cms.ecc.ECCelerateProvider");
167          } catch (Throwable t) {
168            throw new NoSuchProviderException("iaik.cms.ecc.ECCelerateProvider not available: " + t.toString());
169          }
170          Security.insertProviderAt(eccProvider, 1);
171          iaikEccProvider = (IaikProvider)iaikCmsEccelerateProviderCl.newInstance();
172          try {
173            // for the demos we disable SP80057 security strength recommendation checks
174            Method[] methods = eccelerateProviderCl.getDeclaredMethods();
175            Method method = eccelerateProviderCl.getDeclaredMethod("enforceSP80057Recommendations", new Class[] {boolean.class});
176            method.invoke(eccelerateProviderCl, new Object[] { Boolean.FALSE });
177          } catch (Throwable t) {
178            // ignore; run with SP80057 recommendations enforced
179          }
180       
181          try {
182            // set default compression format to uncompressed
183            Class pointEncodersCl = null;
184            pointEncodersCl = Class.forName("iaik.security.ec.common.PointEncoders");
185            Method method = pointEncodersCl.getDeclaredMethod("setDefaultPointEncoder", new Class[] {pointEncodersCl});
186            Field field = pointEncodersCl.getDeclaredField("UNCOMPRESSED");
187            Object obj = field.get(pointEncodersCl);
188            method.invoke(pointEncodersCl, new Object[] { obj });
189          } catch (Throwable t) {
190            System.out.println("Warning: could not set \"uncompressed\" as default compression format for ECCelerate: " + t.toString());
191          }
192          try {
193            // set default domain parameter encoding as OID
194            Class ecParameterSpecCl = null;
195            ecParameterSpecCl = Class.forName("iaik.security.ec.common.ECParameterSpec");
196            Method method = ecParameterSpecCl.getDeclaredMethod("setDefaultOIDEncoding", new Class[] {boolean.class});
197            method.invoke(ecParameterSpecCl, new Object[] { Boolean.TRUE });
198          } catch (Throwable t) {
199            System.out.println("Warning: could not set oid as default demoan parameter encoding for ECCelerate: " + t.toString());
200          }
201          
202          iaikEccProvider_ = iaikEccProvider;
203        } 
204        SecurityProvider.setSecurityProvider(iaikEccProvider_);
205        return iaikEccProvider_;
206      }
207      
208      /**
209       * Gets the version of the IAIK ECCelerate provider (if used).
210       * 
211       * @return the version of the IAIK ECCelerate provider or -1 if
212       *         IAIK ECCelerate is not used
213       */
214      public static double getECCelerateVersion() {
215        double version = -1;
216        if (eccelerateVersion_ != null) {
217          version = eccelerateVersion_.doubleValue();
218        } else {
219          SecurityProvider iaikEccProvider = SecurityProvider.getSecurityProvider();
220          if ("iaik.cms.ecc.ECCelerateProvider".equals(iaikEccProvider.getClass().getName())) {
221            Provider eccelerate = Security.getProvider("IAIK ECCelerate");
222            if (eccelerate != null) {
223              version = eccelerate.getVersion();
224              version = 6.2;
225              eccelerateVersion_ = new Double(version);
226            }  
227          }   
228        }
229        return version;
230      }
231      
232      /**
233       * Creates an EC AlgorithmParameterSpec for the given curve name.
234       * 
235       * @param curveName the name of the curve
236       * 
237       * @return the AlgorithmParameterSpec
238       * 
239       * @throws InvalidParameterSpecException if no AlgorithmParameterSpec for the given curve name is
240       *                                            available or cannot be created 
241       */
242      public static AlgorithmParameterSpec createParamSpec(String curveName) throws InvalidParameterSpecException {
243        AlgorithmParameterSpec paramSpec = null;
244        SecurityProvider provider = SecurityProvider.getSecurityProvider();
245        paramSpec = provider.getEllipticCurveParameterSpec(curveName);
246        return paramSpec;
247      }
248      
249      /**
250       * Signs the given certificate with deterministic generation of parameter k (if supported).
251       * 
252       * 
253       * @param cert the certificate to be signed
254       * @param algorithm the signature algorithm
255       * @param issuerPK the issuer private key
256       * @throws NoSuchAlgorithmException 
257       * @throws CertificateException 
258       * @throws InvalidKeyException 
259       * 
260       */
261      public static void signCertificate(X509Certificate cert, AlgorithmID algorithm, PrivateKey issuerPK) 
262        throws InvalidKeyException, CertificateException, NoSuchAlgorithmException {
263        boolean eccelerateAvailable = true;
264        try {
265          installIaikEccelerateProvider();
266        } catch (Exception e) {
267          eccelerateAvailable = false;
268        }
269        if (eccelerateAvailable) {
270          String providerName = "IAIK ECCelerate";
271          if (algorithm.getName().startsWith("ecdsa")) {
272            // RFC 8550 recommends to use deterministic signing for ECDSA; 
273            // we create a DeterministicSigning AlgorithmParameterSpec object using reflection here;
274            // generally we could simply use the default constructor:
275            // DeterministicSigning deterministicSigning = new DeterministicSigning();
276            
277            AlgorithmParameterSpec deterministicSigning = null;
278            try {
279              Class deterministicSigningCl = Class.forName("iaik.security.ec.ecdsa.DeterministicSigning");
280              Constructor defaultConstructor = deterministicSigningCl.getConstructor(new Class[] { });
281              deterministicSigning = (AlgorithmParameterSpec)defaultConstructor.newInstance(new Object[] { });
282            } catch (Exception e) {
283              // ignore; deterministic signing not available; sign in conventional way
284            }
285            try {
286              cert.sign(algorithm, issuerPK, deterministicSigning, providerName);
287            } catch (InvalidAlgorithmParameterException e) {
288              throw new CertificateException("Error when deterministic signing: " + e.toString());
289            }
290            
291          }
292        } else {
293          cert.sign(algorithm, issuerPK);
294        }
295      }
296      
297      
298      /**
299       * Gets the version number of the current JDK.
300       * 
301       * @return the JDK version number
302       */
303      static public String getJDKVersion() {
304        return (String)System.getProperties().get("java.version");
305      }
306    
307    }
308    
309