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 }