1 /*
  2  * Copyright (c) 2018, 2020, 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         "SHA3-512",
 58         "SHA-512",
 59         "SHA3-384",
 60         "SHA-384",
 61         "SHA3-256",
 62         "SHA-256",
 63         "SHA-512/256",
 64         "SHA3-224",
 65         "SHA-224",
 66         "SHA-512/224",
 67         "SHA-1",
 68         "MD2", "MD5" // these aren't supported by RSA PSS
 69     };
 70 
 71     // indice for message digest algorithms lookup
 72     // may need to be adjusted if new algorithms are added
 73     private static final int PKCS1_5_INDEX_768 = 0; // 512, 384-bit digests
 74     private static final int PKCS1_5_INDEX_512 = 4; // 256-bit digests
 75     private static final int PKCS1_5_INDEX_END = DIGEST_ALGS.length;
 76     private static final int PSS_INDEX_2048 = 0; // 512-bit digests
 77     private static final int PSS_INDEX_1024 = 2; // 384-bit digests
 78     private static final int PSS_INDEX_768 = 4; // 256-bit digests
 79     private static final int PSS_INDEX_512 = 7; // 224-bit digests
 80     private static final int PSS_INDEX_END = DIGEST_ALGS.length - 2;
 81 
 82     public static Iterable<String> getDigestAlgorithms(SignatureType type,
 83             int keysize) throws RuntimeException {
 84 
 85         // initialize to all, then trim based on key size
 86         List<String> result = new ArrayList<>(Arrays.asList(DIGEST_ALGS));
 87         int index = 0;
 88         switch (type) {
 89         case RSA:
 90             if (keysize >= 768) {
 91                 index = PKCS1_5_INDEX_768;
 92             } else if (keysize >= 512) {
 93                 index = PKCS1_5_INDEX_512;
 94             } else {
 95                 throw new RuntimeException("Keysize too small: " + keysize);
 96             }
 97             result = result.subList(index, PKCS1_5_INDEX_END);
 98             break;
 99         case RSASSA_PSS:
100             if (keysize >= 2048) {
101                 index = PSS_INDEX_2048;
102             } else if (keysize >= 1024) {
103                 index = PSS_INDEX_1024;
104             } else if (keysize >= 768) {
105                 index = PSS_INDEX_768;
106             } else if (keysize >= 512) {
107                 index = PSS_INDEX_512;
108             } else {
109                 throw new RuntimeException("Keysize too small: " + keysize);
110             }
111             result = result.subList(index, PSS_INDEX_END);
112             break;
113         default:
114             // XXX maybe just return result instead of error out?
115             throw new RuntimeException("Unsupported signature type: " + type);
116         }
117         return result;
118     }
119 
120     public static AlgorithmParameterSpec generateDefaultParameter(
121             SignatureType type, String mdAlg) throws RuntimeException {
122         // only RSASSA-PSS signature uses parameters
123         switch (type) {
124         case RSASSA_PSS:
125             try {
126                 MessageDigest md = MessageDigest.getInstance(mdAlg);
127                 return new PSSParameterSpec(mdAlg, "MGF1",
128                     new MGF1ParameterSpec(mdAlg), md.getDigestLength(),
129                     PSSParameterSpec.TRAILER_FIELD_BC);
130             } catch (Exception e) {
131                 throw new RuntimeException(e);
132             }
133         default:
134             return null;
135         }
136     }
137 
138     public static String generateSigAlg(SignatureType type,
139             String mdAlg) throws RuntimeException {
140         switch (type) {
141         case RSA:
142             if (mdAlg.startsWith("SHA-")) {
143                 mdAlg = mdAlg.substring(0, 3) + mdAlg.substring(4);
144             }
145             return mdAlg + "with" + type.toString();
146         case RSASSA_PSS:
147             return type.toString();
148         default:
149             throw new RuntimeException("Unsupported signature type " + type );
150         }
151     }
152 
153 }