1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package jdk.test.lib;
  25 
  26 import java.security.*;
  27 import java.security.spec.*;
  28 import java.util.*;
  29 
  30 /*
  31  * Utility class used by various Signature related regression tests for
  32  * common functions such as generating the list of to-be-tested algorithms
  33  * based on key size, etc. Currently, this is mostly needed by RSA
  34  * signatures.
  35  */
  36 public class SigTestUtil {
  37 
  38     public enum SignatureType {
  39         RSA("RSA"),
  40         RSASSA_PSS("RSASSA-PSS")
  41         ;
  42 
  43         private String keyAlg;
  44 
  45         SignatureType(String keyAlg) {
  46             this.keyAlg = keyAlg;
  47         }
  48         @Override
  49         public String toString() {
  50             return keyAlg;
  51         }
  52     }
  53 
  54     // collection of all supported digest algorithms
  55     // note that the entries are ordered by required key sizes
  56     private static final String[] DIGEST_ALGS = {
  57         "SHA-512",
  58         "SHA-384",
  59         "SHA-256",
  60         "SHA-512/256",
  61         "SHA-224",
  62         "SHA-512/224",
  63         "SHA-1",
  64         "MD2", "MD5" // these aren't supported by RSA PSS
  65     };
  66 
  67     // indice for message digest algorithms lookup
  68     // may need to be adjusted if new algorithms are added
  69     private static final int PKCS1_5_INDEX_768 = 0;
  70     private static final int PKCS1_5_INDEX_512 = 2;
  71     private static final int PKCS1_5_INDEX_END = DIGEST_ALGS.length;
  72     private static final int PSS_INDEX_2048 = 0;
  73     private static final int PSS_INDEX_1024 = 1;
  74     private static final int PSS_INDEX_768 = 2;
  75     private static final int PSS_INDEX_512 = 4;
  76     private static final int PSS_INDEX_END = 7;
  77 
  78     public static Iterable<String> getDigestAlgorithms(SignatureType type,
  79             int keysize) throws RuntimeException {
  80 
  81         // initialize to all, then trim based on key size
  82         List<String> result = new ArrayList<>(Arrays.asList(DIGEST_ALGS));
  83         int index = 0;
  84         switch (type) {
  85         case RSA:
  86             if (keysize >= 768) {
  87                 index = PKCS1_5_INDEX_768;
  88             } else if (keysize >= 512) {
  89                 index = PKCS1_5_INDEX_512;
  90             } else {
  91                 throw new RuntimeException("Keysize too small: " + keysize);
  92             }
  93             result = result.subList(index, PKCS1_5_INDEX_END);
  94             break;
  95         case RSASSA_PSS:
  96             if (keysize >= 2048) {
  97                 index = PSS_INDEX_2048;
  98             } else if (keysize >= 1024) {
  99                 index = PSS_INDEX_1024;
 100             } else if (keysize >= 768) {
 101                 index = PSS_INDEX_768;
 102             } else if (keysize >= 512) {
 103                 index = PSS_INDEX_512;
 104             } else {
 105                 throw new RuntimeException("Keysize too small: " + keysize);
 106             }
 107             result = result.subList(index, PSS_INDEX_END);
 108             break;
 109         default:
 110             // XXX maybe just return result instead of error out?
 111             throw new RuntimeException("Unsupported signature type: " + type);
 112         }
 113         return result;
 114     }
 115 
 116     public static AlgorithmParameterSpec generateDefaultParameter(
 117             SignatureType type, String mdAlg) throws RuntimeException {
 118         // only RSASSA-PSS signature uses parameters
 119         switch (type) {
 120         case RSASSA_PSS:
 121             try {
 122                 MessageDigest md = MessageDigest.getInstance(mdAlg);
 123                 return new PSSParameterSpec(mdAlg, "MGF1",
 124                     new MGF1ParameterSpec(mdAlg), md.getDigestLength(),
 125                     PSSParameterSpec.TRAILER_FIELD_BC);
 126             } catch (Exception e) {
 127                 throw new RuntimeException(e);
 128             }
 129         default:
 130             return null;
 131         }
 132     }
 133 
 134     public static String generateSigAlg(SignatureType type,
 135             String mdAlg) throws RuntimeException {
 136         switch (type) {
 137         case RSA:
 138             int idx = mdAlg.indexOf("-");
 139             if (idx != -1) {
 140                 mdAlg = mdAlg.substring(0, idx) + mdAlg.substring(idx+1);
 141             }
 142             return mdAlg + "with" + type.toString();
 143         case RSASSA_PSS:
 144             return type.toString();
 145         default:
 146             throw new RuntimeException("Unsupported signature type " + type );
 147         }
 148     }
 149 
 150 }