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 }