33 import java.text.Collator;
34 import java.text.MessageFormat;
35 import java.security.cert.Certificate;
36 import java.security.cert.X509Certificate;
37 import java.security.cert.CertificateException;
38 import java.security.*;
39
40 import java.net.SocketTimeoutException;
41 import java.net.URL;
42 import java.security.cert.CertPath;
43 import java.security.cert.CertPathValidator;
44 import java.security.cert.CertificateExpiredException;
45 import java.security.cert.CertificateFactory;
46 import java.security.cert.CertificateNotYetValidException;
47 import java.security.cert.PKIXParameters;
48 import java.security.cert.TrustAnchor;
49 import java.util.Map.Entry;
50
51 import jdk.security.jarsigner.JarSigner;
52 import jdk.security.jarsigner.JarSignerException;
53 import sun.security.tools.KeyStoreUtil;
54 import sun.security.x509.*;
55 import sun.security.util.*;
56
57
58 /**
59 * <p>The jarsigner utility.
60 *
61 * The exit codes for the main method are:
62 *
63 * 0: success
64 * 1: any error that the jar cannot be signed or verified, including:
65 * keystore loading error
66 * TSP communication error
67 * jarsigner command line error...
68 * otherwise: error codes from -strict
69 *
70 * @author Roland Schemers
71 * @author Jan Luehe
72 */
73 public class Main {
74
75 // for i18n
76 private static final java.util.ResourceBundle rb =
77 java.util.ResourceBundle.getBundle
78 ("sun.security.tools.jarsigner.Resources");
79 private static final Collator collator = Collator.getInstance();
80 static {
81 // this is for case insensitive string comparisions
82 collator.setStrength(Collator.PRIMARY);
83 }
84
85 private static final String NONE = "NONE";
86 private static final String P11KEYSTORE = "PKCS11";
87
88 private static final long SIX_MONTHS = 180*24*60*60*1000L; //milliseconds
89
90 // Attention:
91 // This is the entry that get launched by the security tool jarsigner.
92 public static void main(String args[]) throws Exception {
93 Main js = new Main();
94 js.run(args);
95 }
96
97 static final String VERSION = "1.0";
98
99 static final int IN_KEYSTORE = 0x01; // signer is in keystore
100 static final int NOT_ALIAS = 0x04; // alias list is NOT empty and
101 // signer is not in alias list
102 static final int SIGNED_BY_ALIAS = 0x08; // signer is in alias list
103
104 X509Certificate[] certChain; // signer's cert chain (when composing)
105 PrivateKey privateKey; // private key
106 KeyStore store; // the keystore specified by -keystore
107 // or the default keystore, never null
108
109 String keystore; // key store file
146 // Informational warnings
147 private boolean hasExpiringCert = false;
148 private boolean noTimestamp = false;
149 private Date expireDate = new Date(0L); // used in noTimestamp warning
150
151 // Severe warnings
152 private int weakAlg = 0; // 1. digestalg, 2. sigalg, 4. tsadigestalg
153 private boolean hasExpiredCert = false;
154 private boolean notYetValidCert = false;
155 private boolean chainNotValidated = false;
156 private boolean notSignedByAlias = false;
157 private boolean aliasNotInStore = false;
158 private boolean hasUnsignedEntry = false;
159 private boolean badKeyUsage = false;
160 private boolean badExtendedKeyUsage = false;
161 private boolean badNetscapeCertType = false;
162 private boolean signerSelfSigned = false;
163
164 private Throwable chainNotValidatedReason = null;
165
166 CertificateFactory certificateFactory;
167 CertPathValidator validator;
168 PKIXParameters pkixParameters;
169
170 public void run(String args[]) {
171 try {
172 args = parseArgs(args);
173
174 // Try to load and install the specified providers
175 if (providers != null) {
176 for (String provName: providers) {
177 try {
178 KeyStoreUtil.loadProviderByName(provName,
179 providerArgs.get(provName));
180 if (debug) {
181 System.out.println("loadProviderByName: " + provName);
182 }
183 } catch (IllegalArgumentException e) {
184 throw new Exception(String.format(rb.getString(
185 "provider.name.not.found"), provName));
611 System.out.println(rb.getString
612 (".providerClass.option"));
613 System.out.println(rb.getString
614 (".providerArg.option.2"));
615 System.out.println();
616 System.out.println(rb.getString
617 (".strict.treat.warnings.as.errors"));
618 System.out.println();
619 System.out.println(rb.getString
620 (".conf.url.specify.a.pre.configured.options.file"));
621 System.out.println();
622
623 System.exit(0);
624 }
625
626 void verifyJar(String jarName)
627 throws Exception
628 {
629 boolean anySigned = false; // if there exists entry inside jar signed
630 JarFile jf = null;
631
632 try {
633 jf = new JarFile(jarName, true);
634 Vector<JarEntry> entriesVec = new Vector<>();
635 byte[] buffer = new byte[8192];
636
637 Enumeration<JarEntry> entries = jf.entries();
638 while (entries.hasMoreElements()) {
639 JarEntry je = entries.nextElement();
640 entriesVec.addElement(je);
641 InputStream is = null;
642 try {
643 is = jf.getInputStream(je);
644 while (is.read(buffer, 0, buffer.length) != -1) {
645 // we just read. this will throw a SecurityException
646 // if a signature/digest check fails.
647 }
648 } finally {
649 if (is != null) {
650 is.close();
651 }
652 }
653 }
654
655 Manifest man = jf.getManifest();
656 boolean hasSignature = false;
657
658 // The map to record display info, only used when -verbose provided
659 // key: signer info string
660 // value: the list of files with common key
661 Map<String,List<String>> output = new LinkedHashMap<>();
662
663 if (man != null) {
664 if (verbose != null) System.out.println();
665 Enumeration<JarEntry> e = entriesVec.elements();
666
667 String tab = rb.getString("6SPACE");
668
669 while (e.hasMoreElements()) {
670 JarEntry je = e.nextElement();
788 String.format(rb.getString(
789 ".and.d.more."), files.size()-1));
790 } else {
791 System.out.println(files.get(0));
792 }
793 }
794 System.out.printf(key.substring(pipe+1));
795 }
796 }
797 System.out.println();
798 System.out.println(rb.getString(
799 ".s.signature.was.verified."));
800 System.out.println(rb.getString(
801 ".m.entry.is.listed.in.manifest"));
802 System.out.println(rb.getString(
803 ".k.at.least.one.certificate.was.found.in.keystore"));
804 if (ckaliases.size() > 0) {
805 System.out.println(rb.getString(
806 ".X.not.signed.by.specified.alias.es."));
807 }
808 System.out.println();
809 }
810 if (man == null)
811 System.out.println(rb.getString("no.manifest."));
812
813 // If signer is a trusted cert or private entry in user's own
814 // keystore, it can be self-signed.
815 if (!aliasNotInStore) {
816 signerSelfSigned = false;
817 }
818
819 if (!anySigned) {
820 if (hasSignature) {
821 System.out.println(rb.getString("jar.treated.unsigned"));
822 } else {
823 System.out.println(rb.getString("jar.is.unsigned"));
824 }
825 } else {
826 boolean warningAppeared = false;
827 boolean errorAppeared = false;
828 if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
829 notYetValidCert || chainNotValidated || hasExpiredCert ||
830 hasUnsignedEntry || signerSelfSigned || (weakAlg != 0) ||
831 aliasNotInStore || notSignedByAlias) {
832
833 if (strict) {
834 System.out.println(rb.getString("jar.verified.with.signer.errors."));
835 System.out.println();
836 System.out.println(rb.getString("Error."));
837 errorAppeared = true;
838 } else {
839 System.out.println(rb.getString("jar.verified."));
840 System.out.println();
841 System.out.println(rb.getString("Warning."));
842 warningAppeared = true;
843 }
844
845 if (weakAlg != 0) {
846 // In fact, jarsigner verification did not catch this
847 // since it has not read the JarFile content itself.
848 // Everything is done with JarFile API.
849 }
850
851 if (badKeyUsage) {
852 System.out.println(
853 rb.getString("This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));
854 }
855
856 if (badExtendedKeyUsage) {
857 System.out.println(
858 rb.getString("This.jar.contains.entries.whose.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."));
859 }
860
861 if (badNetscapeCertType) {
862 System.out.println(
863 rb.getString("This.jar.contains.entries.whose.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."));
864 }
865
866 if (hasUnsignedEntry) {
867 System.out.println(rb.getString(
868 "This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked."));
919 System.out.println(rb.getString(
920 "Re.run.with.the.verbose.and.certs.options.for.more.details."));
921 }
922 }
923 }
924 return;
925 } catch (Exception e) {
926 System.out.println(rb.getString("jarsigner.") + e);
927 if (debug) {
928 e.printStackTrace();
929 }
930 } finally { // close the resource
931 if (jf != null) {
932 jf.close();
933 }
934 }
935
936 System.exit(1);
937 }
938
939 private static MessageFormat validityTimeForm = null;
940 private static MessageFormat notYetTimeForm = null;
941 private static MessageFormat expiredTimeForm = null;
942 private static MessageFormat expiringTimeForm = null;
943
944 /*
945 * Display some details about a certificate:
946 *
947 * [<tab>] <cert-type> [", " <subject-DN>] [" (" <keystore-entry-alias> ")"]
948 * [<validity-period> | <expiry-warning>]
949 *
950 * Note: no newline character at the end
951 */
952 String printCert(String tab, Certificate c, boolean checkValidityPeriod,
953 Date timestamp, boolean checkUsage) {
954
955 StringBuilder certStr = new StringBuilder();
956 String space = rb.getString("SPACE");
957 X509Certificate x509Cert = null;
958
1108 int inKeyStore(CodeSigner[] signers) {
1109
1110 if (signers == null)
1111 return 0;
1112
1113 int output = 0;
1114
1115 for (CodeSigner signer: signers) {
1116 int result = inKeyStoreForOneSigner(signer);
1117 output |= result;
1118 }
1119 if (ckaliases.size() > 0 && (output & SIGNED_BY_ALIAS) == 0) {
1120 output |= NOT_ALIAS;
1121 }
1122 return output;
1123 }
1124
1125 void signJar(String jarName, String alias)
1126 throws Exception {
1127
1128 DisabledAlgorithmConstraints dac =
1129 new DisabledAlgorithmConstraints(
1130 DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
1131
1132 if (digestalg != null && !dac.permits(
1133 Collections.singleton(CryptoPrimitive.MESSAGE_DIGEST), digestalg, null)) {
1134 weakAlg |= 1;
1135 }
1136 if (tSADigestAlg != null && !dac.permits(
1137 Collections.singleton(CryptoPrimitive.MESSAGE_DIGEST), tSADigestAlg, null)) {
1138 weakAlg |= 4;
1139 }
1140 if (sigalg != null && !dac.permits(
1141 Collections.singleton(CryptoPrimitive.SIGNATURE), sigalg, null)) {
1142 weakAlg |= 2;
1143 }
1144
1145 boolean aliasUsed = false;
1146 X509Certificate tsaCert = null;
1147
1148 if (sigfile == null) {
1149 sigfile = alias;
1150 aliasUsed = true;
1151 }
1152
1153 if (sigfile.length() > 8) {
1154 sigfile = sigfile.substring(0, 8).toUpperCase(Locale.ENGLISH);
1155 } else {
1156 sigfile = sigfile.toUpperCase(Locale.ENGLISH);
1157 }
1158
1159 StringBuilder tmpSigFile = new StringBuilder(sigfile.length());
1160 for (int j = 0; j < sigfile.length(); j++) {
1161 char c = sigfile.charAt(j);
1162 if (!
1163 ((c>= 'A' && c<= 'Z') ||
1368 System.out.println(
1369 rb.getString("The.signer.s.certificate.is.self.signed."));
1370 }
1371
1372 if ((weakAlg & 1) == 1) {
1373 System.out.println(String.format(
1374 rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
1375 digestalg, "-digestalg"));
1376 }
1377
1378 if ((weakAlg & 2) == 2) {
1379 System.out.println(String.format(
1380 rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
1381 sigalg, "-sigalg"));
1382 }
1383 if ((weakAlg & 4) == 4) {
1384 System.out.println(String.format(
1385 rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
1386 tSADigestAlg, "-tsadigestalg"));
1387 }
1388 } else {
1389 System.out.println(rb.getString("jar.signed."));
1390 }
1391 if (hasExpiringCert || noTimestamp) {
1392 if (!warningAppeared) {
1393 System.out.println();
1394 System.out.println(rb.getString("Warning."));
1395 }
1396
1397 if (hasExpiringCert) {
1398 System.out.println(
1399 rb.getString("The.signer.certificate.will.expire.within.six.months."));
1400 }
1401
1402 if (noTimestamp) {
1403 System.out.println(
1404 String.format(rb.getString("no.timestamp.signing"), expireDate));
1405 }
1406 }
1407
|
33 import java.text.Collator;
34 import java.text.MessageFormat;
35 import java.security.cert.Certificate;
36 import java.security.cert.X509Certificate;
37 import java.security.cert.CertificateException;
38 import java.security.*;
39
40 import java.net.SocketTimeoutException;
41 import java.net.URL;
42 import java.security.cert.CertPath;
43 import java.security.cert.CertPathValidator;
44 import java.security.cert.CertificateExpiredException;
45 import java.security.cert.CertificateFactory;
46 import java.security.cert.CertificateNotYetValidException;
47 import java.security.cert.PKIXParameters;
48 import java.security.cert.TrustAnchor;
49 import java.util.Map.Entry;
50
51 import jdk.security.jarsigner.JarSigner;
52 import jdk.security.jarsigner.JarSignerException;
53 import sun.security.pkcs.PKCS7;
54 import sun.security.pkcs.SignerInfo;
55 import sun.security.timestamp.TimestampToken;
56 import sun.security.tools.KeyStoreUtil;
57 import sun.security.x509.*;
58 import sun.security.util.*;
59
60
61 /**
62 * <p>The jarsigner utility.
63 *
64 * The exit codes for the main method are:
65 *
66 * 0: success
67 * 1: any error that the jar cannot be signed or verified, including:
68 * keystore loading error
69 * TSP communication error
70 * jarsigner command line error...
71 * otherwise: error codes from -strict
72 *
73 * @author Roland Schemers
74 * @author Jan Luehe
75 */
76 public class Main {
77
78 // for i18n
79 private static final java.util.ResourceBundle rb =
80 java.util.ResourceBundle.getBundle
81 ("sun.security.tools.jarsigner.Resources");
82 private static final Collator collator = Collator.getInstance();
83 static {
84 // this is for case insensitive string comparisions
85 collator.setStrength(Collator.PRIMARY);
86 }
87
88 private static final String NONE = "NONE";
89 private static final String P11KEYSTORE = "PKCS11";
90
91 private static final long SIX_MONTHS = 180*24*60*60*1000L; //milliseconds
92
93 // PROPERTY_CERTPATH_DISABLED_ALGS is currently more restrictive than
94 // PROPERTY_JAR_DISABLED_ALGS and we used it at signing time.
95 private static final DisabledAlgorithmConstraints VERIFY_CHECK =
96 new DisabledAlgorithmConstraints(
97 DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS);
98 private static final DisabledAlgorithmConstraints SIGN_CHECK =
99 new DisabledAlgorithmConstraints(
100 DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
101
102 private static final Set<CryptoPrimitive> DIGEST_PRIMITIVE_SET = Collections
103 .unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST));
104 private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET = Collections
105 .unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
106
107 // Attention:
108 // This is the entry that get launched by the security tool jarsigner.
109 public static void main(String args[]) throws Exception {
110 Main js = new Main();
111 js.run(args);
112 }
113
114 static final String VERSION = "1.0";
115
116 static final int IN_KEYSTORE = 0x01; // signer is in keystore
117 static final int NOT_ALIAS = 0x04; // alias list is NOT empty and
118 // signer is not in alias list
119 static final int SIGNED_BY_ALIAS = 0x08; // signer is in alias list
120
121 X509Certificate[] certChain; // signer's cert chain (when composing)
122 PrivateKey privateKey; // private key
123 KeyStore store; // the keystore specified by -keystore
124 // or the default keystore, never null
125
126 String keystore; // key store file
163 // Informational warnings
164 private boolean hasExpiringCert = false;
165 private boolean noTimestamp = false;
166 private Date expireDate = new Date(0L); // used in noTimestamp warning
167
168 // Severe warnings
169 private int weakAlg = 0; // 1. digestalg, 2. sigalg, 4. tsadigestalg
170 private boolean hasExpiredCert = false;
171 private boolean notYetValidCert = false;
172 private boolean chainNotValidated = false;
173 private boolean notSignedByAlias = false;
174 private boolean aliasNotInStore = false;
175 private boolean hasUnsignedEntry = false;
176 private boolean badKeyUsage = false;
177 private boolean badExtendedKeyUsage = false;
178 private boolean badNetscapeCertType = false;
179 private boolean signerSelfSigned = false;
180
181 private Throwable chainNotValidatedReason = null;
182
183 private boolean seeWeak = false;
184
185 CertificateFactory certificateFactory;
186 CertPathValidator validator;
187 PKIXParameters pkixParameters;
188
189 public void run(String args[]) {
190 try {
191 args = parseArgs(args);
192
193 // Try to load and install the specified providers
194 if (providers != null) {
195 for (String provName: providers) {
196 try {
197 KeyStoreUtil.loadProviderByName(provName,
198 providerArgs.get(provName));
199 if (debug) {
200 System.out.println("loadProviderByName: " + provName);
201 }
202 } catch (IllegalArgumentException e) {
203 throw new Exception(String.format(rb.getString(
204 "provider.name.not.found"), provName));
630 System.out.println(rb.getString
631 (".providerClass.option"));
632 System.out.println(rb.getString
633 (".providerArg.option.2"));
634 System.out.println();
635 System.out.println(rb.getString
636 (".strict.treat.warnings.as.errors"));
637 System.out.println();
638 System.out.println(rb.getString
639 (".conf.url.specify.a.pre.configured.options.file"));
640 System.out.println();
641
642 System.exit(0);
643 }
644
645 void verifyJar(String jarName)
646 throws Exception
647 {
648 boolean anySigned = false; // if there exists entry inside jar signed
649 JarFile jf = null;
650 Map<String,String> digestMap = new HashMap<>();
651 Map<String,PKCS7> sigMap = new HashMap<>();
652 Map<String,String> sigNameMap = new HashMap<>();
653 Map<String,String> unparsableSignatures = new HashMap<>();
654
655 try {
656 jf = new JarFile(jarName, true);
657 Vector<JarEntry> entriesVec = new Vector<>();
658 byte[] buffer = new byte[8192];
659
660 Enumeration<JarEntry> entries = jf.entries();
661 while (entries.hasMoreElements()) {
662 JarEntry je = entries.nextElement();
663 entriesVec.addElement(je);
664 try (InputStream is = jf.getInputStream(je)) {
665 String name = je.getName();
666 if (signatureRelated(name)
667 && SignatureFileVerifier.isBlockOrSF(name)) {
668 String alias = name.substring(name.lastIndexOf('/') + 1,
669 name.lastIndexOf('.'));
670 try {
671 if (name.endsWith(".SF")) {
672 Manifest sf = new Manifest(is);
673 boolean found = false;
674 for (Object obj : sf.getMainAttributes().keySet()) {
675 String key = obj.toString();
676 if (key.endsWith("-Digest-Manifest")) {
677 digestMap.put(alias,
678 key.substring(0, key.length() - 16));
679 found = true;
680 break;
681 }
682 }
683 if (!found) {
684 unparsableSignatures.putIfAbsent(alias,
685 String.format(
686 rb.getString("history.unparsable"),
687 name));
688 }
689 } else {
690 sigNameMap.put(alias, name);
691 sigMap.put(alias, new PKCS7(is));
692 }
693 } catch (IOException ioe) {
694 unparsableSignatures.putIfAbsent(alias, String.format(
695 rb.getString("history.unparsable"), name));
696 }
697 } else {
698 while (is.read(buffer, 0, buffer.length) != -1) {
699 // we just read. this will throw a SecurityException
700 // if a signature/digest check fails.
701 }
702 }
703 }
704 }
705
706 Manifest man = jf.getManifest();
707 boolean hasSignature = false;
708
709 // The map to record display info, only used when -verbose provided
710 // key: signer info string
711 // value: the list of files with common key
712 Map<String,List<String>> output = new LinkedHashMap<>();
713
714 if (man != null) {
715 if (verbose != null) System.out.println();
716 Enumeration<JarEntry> e = entriesVec.elements();
717
718 String tab = rb.getString("6SPACE");
719
720 while (e.hasMoreElements()) {
721 JarEntry je = e.nextElement();
839 String.format(rb.getString(
840 ".and.d.more."), files.size()-1));
841 } else {
842 System.out.println(files.get(0));
843 }
844 }
845 System.out.printf(key.substring(pipe+1));
846 }
847 }
848 System.out.println();
849 System.out.println(rb.getString(
850 ".s.signature.was.verified."));
851 System.out.println(rb.getString(
852 ".m.entry.is.listed.in.manifest"));
853 System.out.println(rb.getString(
854 ".k.at.least.one.certificate.was.found.in.keystore"));
855 if (ckaliases.size() > 0) {
856 System.out.println(rb.getString(
857 ".X.not.signed.by.specified.alias.es."));
858 }
859 }
860 if (man == null) {
861 System.out.println();
862 System.out.println(rb.getString("no.manifest."));
863 }
864
865 // If signer is a trusted cert or private entry in user's own
866 // keystore, it can be self-signed.
867 if (!aliasNotInStore) {
868 signerSelfSigned = false;
869 }
870
871 // Even if the verbose option is not specified, all out strings
872 // must be generated so seeWeak can be updated.
873 if (!digestMap.isEmpty()
874 || !sigMap.isEmpty()
875 || !unparsableSignatures.isEmpty()) {
876 if (verbose != null) {
877 System.out.println();
878 }
879 for (String s : sigMap.keySet()) {
880 if (!digestMap.containsKey(s)) {
881 unparsableSignatures.putIfAbsent(s, String.format(
882 rb.getString("history.nosf"), s));
883 }
884 }
885 for (String s : digestMap.keySet()) {
886 PKCS7 p7 = sigMap.get(s);
887 if (p7 != null) {
888 String history;
889 try {
890 SignerInfo si = p7.getSignerInfos()[0];
891 X509Certificate signer = si.getCertificate(p7);
892 String digestAlg = digestMap.get(s);
893 String sigAlg = AlgorithmId.makeSigAlg(
894 si.getDigestAlgorithmId().getName(),
895 si.getDigestEncryptionAlgorithmId().getName());
896 PublicKey key = signer.getPublicKey();
897 PKCS7 tsToken = si.getTsToken();
898 if (tsToken != null) {
899 SignerInfo tsSi = tsToken.getSignerInfos()[0];
900 X509Certificate tsSigner = tsSi.getCertificate(tsToken);
901 byte[] encTsTokenInfo = tsToken.getContentInfo().getData();
902 TimestampToken tsTokenInfo = new TimestampToken(encTsTokenInfo);
903 PublicKey tsKey = tsSigner.getPublicKey();
904 String tsDigestAlg = tsTokenInfo.getHashAlgorithm().getName();
905 String tsSigAlg = AlgorithmId.makeSigAlg(
906 tsSi.getDigestAlgorithmId().getName(),
907 tsSi.getDigestEncryptionAlgorithmId().getName());
908 Calendar c = Calendar.getInstance(
909 TimeZone.getTimeZone("UTC"),
910 Locale.getDefault(Locale.Category.FORMAT));
911 c.setTime(tsTokenInfo.getDate());
912 history = String.format(
913 rb.getString("history.with.ts"),
914 signer.getSubjectX500Principal(),
915 withWeak(digestAlg, DIGEST_PRIMITIVE_SET),
916 withWeak(sigAlg, SIG_PRIMITIVE_SET),
917 withWeak(key),
918 c,
919 tsSigner.getSubjectX500Principal(),
920 withWeak(tsDigestAlg, DIGEST_PRIMITIVE_SET),
921 withWeak(tsSigAlg, SIG_PRIMITIVE_SET),
922 withWeak(tsKey));
923 } else {
924 history = String.format(
925 rb.getString("history.without.ts"),
926 signer.getSubjectX500Principal(),
927 withWeak(digestAlg, DIGEST_PRIMITIVE_SET),
928 withWeak(sigAlg, SIG_PRIMITIVE_SET),
929 withWeak(key));
930 }
931 } catch (Exception e) {
932 // The only usage of sigNameMap, remember the name
933 // of the block file if it's invalid.
934 history = String.format(
935 rb.getString("history.unparsable"),
936 sigNameMap.get(s));
937 }
938 if (verbose != null) {
939 System.out.println(history);
940 }
941 } else {
942 unparsableSignatures.putIfAbsent(s, String.format(
943 rb.getString("history.nobk"), s));
944 }
945 }
946 if (verbose != null) {
947 for (String s : unparsableSignatures.keySet()) {
948 System.out.println(unparsableSignatures.get(s));
949 }
950 }
951 }
952 System.out.println();
953 if (!anySigned) {
954 if (seeWeak) {
955 if (verbose != null) {
956 System.out.println(rb.getString("jar.treated.unsigned.see.weak.verbose"));
957 System.out.println("\n " +
958 DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS +
959 "=" + Security.getProperty(DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS));
960 } else {
961 System.out.println(rb.getString("jar.treated.unsigned.see.weak"));
962 }
963 } else if (hasSignature) {
964 System.out.println(rb.getString("jar.treated.unsigned"));
965 } else {
966 System.out.println(rb.getString("jar.is.unsigned"));
967 }
968 } else {
969 boolean warningAppeared = false;
970 boolean errorAppeared = false;
971 if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
972 notYetValidCert || chainNotValidated || hasExpiredCert ||
973 hasUnsignedEntry || signerSelfSigned || (weakAlg != 0) ||
974 aliasNotInStore || notSignedByAlias) {
975
976 if (strict) {
977 System.out.println(rb.getString("jar.verified.with.signer.errors."));
978 System.out.println();
979 System.out.println(rb.getString("Error."));
980 errorAppeared = true;
981 } else {
982 System.out.println(rb.getString("jar.verified."));
983 System.out.println();
984 System.out.println(rb.getString("Warning."));
985 warningAppeared = true;
986 }
987
988 if (weakAlg != 0) {
989 // In fact, jarsigner verification did not catch this
990 // since it has not read the JarFile content itself.
991 // Everything is done with JarFile API. The signing
992 // history (digestMap etc) will show these info and
993 // print out proper warnings.
994 }
995
996 if (badKeyUsage) {
997 System.out.println(
998 rb.getString("This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));
999 }
1000
1001 if (badExtendedKeyUsage) {
1002 System.out.println(
1003 rb.getString("This.jar.contains.entries.whose.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."));
1004 }
1005
1006 if (badNetscapeCertType) {
1007 System.out.println(
1008 rb.getString("This.jar.contains.entries.whose.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."));
1009 }
1010
1011 if (hasUnsignedEntry) {
1012 System.out.println(rb.getString(
1013 "This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked."));
1064 System.out.println(rb.getString(
1065 "Re.run.with.the.verbose.and.certs.options.for.more.details."));
1066 }
1067 }
1068 }
1069 return;
1070 } catch (Exception e) {
1071 System.out.println(rb.getString("jarsigner.") + e);
1072 if (debug) {
1073 e.printStackTrace();
1074 }
1075 } finally { // close the resource
1076 if (jf != null) {
1077 jf.close();
1078 }
1079 }
1080
1081 System.exit(1);
1082 }
1083
1084 private String withWeak(String alg, Set<CryptoPrimitive> primitiveSet) {
1085 if (VERIFY_CHECK.permits(primitiveSet, alg, null)) {
1086 return alg;
1087 } else {
1088 seeWeak = true;
1089 return String.format(rb.getString("with.weak"), alg);
1090 }
1091 }
1092
1093 private String withWeak(PublicKey key) {
1094 if (VERIFY_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
1095 return String.format(
1096 rb.getString("key.bit"), KeyUtil.getKeySize(key));
1097 } else {
1098 seeWeak = true;
1099 return String.format(
1100 rb.getString("key.bit.weak"), KeyUtil.getKeySize(key));
1101 }
1102 }
1103
1104 private static MessageFormat validityTimeForm = null;
1105 private static MessageFormat notYetTimeForm = null;
1106 private static MessageFormat expiredTimeForm = null;
1107 private static MessageFormat expiringTimeForm = null;
1108
1109 /*
1110 * Display some details about a certificate:
1111 *
1112 * [<tab>] <cert-type> [", " <subject-DN>] [" (" <keystore-entry-alias> ")"]
1113 * [<validity-period> | <expiry-warning>]
1114 *
1115 * Note: no newline character at the end
1116 */
1117 String printCert(String tab, Certificate c, boolean checkValidityPeriod,
1118 Date timestamp, boolean checkUsage) {
1119
1120 StringBuilder certStr = new StringBuilder();
1121 String space = rb.getString("SPACE");
1122 X509Certificate x509Cert = null;
1123
1273 int inKeyStore(CodeSigner[] signers) {
1274
1275 if (signers == null)
1276 return 0;
1277
1278 int output = 0;
1279
1280 for (CodeSigner signer: signers) {
1281 int result = inKeyStoreForOneSigner(signer);
1282 output |= result;
1283 }
1284 if (ckaliases.size() > 0 && (output & SIGNED_BY_ALIAS) == 0) {
1285 output |= NOT_ALIAS;
1286 }
1287 return output;
1288 }
1289
1290 void signJar(String jarName, String alias)
1291 throws Exception {
1292
1293 if (digestalg != null && !SIGN_CHECK.permits(
1294 DIGEST_PRIMITIVE_SET, digestalg, null)) {
1295 weakAlg |= 1;
1296 }
1297 if (tSADigestAlg != null && !SIGN_CHECK.permits(
1298 DIGEST_PRIMITIVE_SET, tSADigestAlg, null)) {
1299 weakAlg |= 4;
1300 }
1301 if (sigalg != null && !SIGN_CHECK.permits(
1302 SIG_PRIMITIVE_SET , sigalg, null)) {
1303 weakAlg |= 2;
1304 }
1305 if (!SIGN_CHECK.permits(
1306 SIG_PRIMITIVE_SET, privateKey)) {
1307 weakAlg |= 8;
1308 }
1309
1310 boolean aliasUsed = false;
1311 X509Certificate tsaCert = null;
1312
1313 if (sigfile == null) {
1314 sigfile = alias;
1315 aliasUsed = true;
1316 }
1317
1318 if (sigfile.length() > 8) {
1319 sigfile = sigfile.substring(0, 8).toUpperCase(Locale.ENGLISH);
1320 } else {
1321 sigfile = sigfile.toUpperCase(Locale.ENGLISH);
1322 }
1323
1324 StringBuilder tmpSigFile = new StringBuilder(sigfile.length());
1325 for (int j = 0; j < sigfile.length(); j++) {
1326 char c = sigfile.charAt(j);
1327 if (!
1328 ((c>= 'A' && c<= 'Z') ||
1533 System.out.println(
1534 rb.getString("The.signer.s.certificate.is.self.signed."));
1535 }
1536
1537 if ((weakAlg & 1) == 1) {
1538 System.out.println(String.format(
1539 rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
1540 digestalg, "-digestalg"));
1541 }
1542
1543 if ((weakAlg & 2) == 2) {
1544 System.out.println(String.format(
1545 rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
1546 sigalg, "-sigalg"));
1547 }
1548 if ((weakAlg & 4) == 4) {
1549 System.out.println(String.format(
1550 rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
1551 tSADigestAlg, "-tsadigestalg"));
1552 }
1553 if ((weakAlg & 8) == 8) {
1554 System.out.println(String.format(
1555 rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk."),
1556 privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey)));
1557 }
1558 } else {
1559 System.out.println(rb.getString("jar.signed."));
1560 }
1561 if (hasExpiringCert || noTimestamp) {
1562 if (!warningAppeared) {
1563 System.out.println();
1564 System.out.println(rb.getString("Warning."));
1565 }
1566
1567 if (hasExpiringCert) {
1568 System.out.println(
1569 rb.getString("The.signer.certificate.will.expire.within.six.months."));
1570 }
1571
1572 if (noTimestamp) {
1573 System.out.println(
1574 String.format(rb.getString("no.timestamp.signing"), expireDate));
1575 }
1576 }
1577
|