1 /* 2 * Copyright (c) 2015, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.security.jarsigner; 27 28 import com.sun.jarsigner.ContentSigner; 29 import sun.security.x509.AlgorithmId; 30 31 import java.net.URI; 32 import java.security.MessageDigest; 33 import java.security.NoSuchAlgorithmException; 34 import java.security.PrivateKey; 35 import java.security.Provider; 36 import java.security.Signature; 37 import java.security.cert.Certificate; 38 import java.security.cert.X509Certificate; 39 import java.util.Locale; 40 41 /** 42 * A utility to build an Action object that contains the actual sign method. 43 * 44 * This class exposes more public methods than JarSigner so that the jarsigner 45 * tool can be based on it. Null check, array cloning, and other checks that 46 * are usually not necessary when called internally are implemented in 47 * JarSigner. Read each method carefully. 48 */ 49 class Builder { 50 51 // Signer materials 52 final PrivateKey privateKey; 53 final X509Certificate[] certChain; 54 55 // Below are all option settings 56 // Common: 57 String[] digestalg; 58 String sigalg; 59 Provider digestProvider; 60 Provider sigProvider; 61 URI tsaUrl; 62 String signerName; 63 // Seldom: 64 String tSAPolicyID; 65 String tSADigestAlg; 66 X509Certificate tsaCert; 67 // Useless: 68 boolean signManifest = true; 69 boolean externalSF = true; 70 ContentSigner signingMechanism; 71 72 EventHandler handler = new EventHandler() {}; 73 74 interface EventHandler { 75 default public void updating(String s) {} 76 default public void adding(String s) {} 77 default public void signing(String s) {} 78 } 79 80 public Builder digestAlg(String alg, Provider provider) 81 throws NoSuchAlgorithmException { 82 // Check availability 83 if (provider == null) { 84 MessageDigest.getInstance(alg); 85 } else { 86 MessageDigest.getInstance(alg, provider); 87 } 88 digestalg = new String[]{alg}; 89 digestProvider = provider; 90 return this; 91 } 92 93 public Builder sigAlg(String signatureAlgorithm, Provider provider) 94 throws NoSuchAlgorithmException, IllegalArgumentException { 95 96 // Check availability 97 if (provider == null) { 98 Signature.getInstance(signatureAlgorithm); 99 } else { 100 Signature.getInstance(signatureAlgorithm, provider); 101 } 102 AlgorithmId.checKeyAlgSigAlgkMatch( 103 privateKey.getAlgorithm(), signatureAlgorithm); 104 this.sigalg = signatureAlgorithm; 105 this.sigProvider = provider; 106 return this; 107 } 108 109 public Builder tsa(URI uri) { 110 this.tsaUrl = uri; 111 return this; 112 } 113 114 public Builder signerName(String name) { 115 if (name.isEmpty() || name.length() > 8) { 116 throw new IllegalArgumentException("Name too long"); 117 } 118 119 name = name.toUpperCase(Locale.ENGLISH); 120 121 for (int j = 0; j < name.length(); j++) { 122 char c = name.charAt(j); 123 if (! 124 ((c >= 'A' && c <= 'Z') || 125 (c >= '0' && c <= '9') || 126 (c == '-') || 127 (c == '_'))) { 128 throw new IllegalArgumentException("Invalid characters in name"); 129 } 130 } 131 this.signerName = name; 132 return this; 133 } 134 135 public static String getDefaultDigestAlg() { 136 return "SHA-256"; 137 } 138 139 // Methods not exposed by JarSigner (yet) 140 public Builder tsaCert(X509Certificate tsaCert) { 141 this.tsaCert = tsaCert; 142 return this; 143 } 144 145 public Builder tsaPolicyId(String oid) { 146 this.tSAPolicyID = oid; 147 return this; 148 } 149 150 public Builder tsaDigestAlg(String alg) throws NoSuchAlgorithmException { 151 if (alg != null) { 152 MessageDigest.getInstance(alg); 153 } 154 this.tSADigestAlg = alg; 155 return this; 156 } 157 158 public Builder altsigner(com.sun.jarsigner.ContentSigner signer) { 159 signingMechanism = signer; 160 return this; 161 } 162 163 public Builder sectionsOnly(boolean v) { 164 signManifest = !v; 165 return this; 166 } 167 168 public Builder internalSF(boolean v) { 169 externalSF = !v; 170 return this; 171 } 172 173 public Builder setEventHandler(EventHandler a) { 174 this.handler = a == null ? new EventHandler() {}: a; 175 return this; 176 } 177 178 public String getDefaultTsaDigestAlg() { 179 return getDefaultDigestAlg(); 180 } 181 182 // Constructor 183 184 public Builder(PrivateKey key, Certificate... certs) { 185 this.privateKey = key; 186 this.certChain = new X509Certificate[certs.length]; 187 for (int i=0; i<certs.length; i++) { 188 certChain[i] = (X509Certificate)certs[i]; 189 } 190 } 191 192 // Builder 193 194 public Action build() { 195 return new Action(this); 196 } 197 }