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