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 private static final DisabledAlgorithmConstraints DISABLED_CHECK =
94 new DisabledAlgorithmConstraints(
95 DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS);
96
97 private static final Set<CryptoPrimitive> DIGEST_PRIMITIVE_SET = Collections
98 .unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST));
99 private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET = Collections
100 .unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
101
102 // Attention:
103 // This is the entry that get launched by the security tool jarsigner.
104 public static void main(String args[]) throws Exception {
105 Main js = new Main();
106 js.run(args);
107 }
108
109 static final String VERSION = "1.0";
110
111 static final int IN_KEYSTORE = 0x01; // signer is in keystore
112 static final int NOT_ALIAS = 0x04; // alias list is NOT empty and
113 // signer is not in alias list
114 static final int SIGNED_BY_ALIAS = 0x08; // signer is in alias list
115
116 X509Certificate[] certChain; // signer's cert chain (when composing)
117 PrivateKey privateKey; // private key
118 KeyStore store; // the keystore specified by -keystore
119 // or the default keystore, never null
120
121 String keystore; // key store file
158 // Informational warnings
159 private boolean hasExpiringCert = false;
160 private boolean noTimestamp = false;
161 private Date expireDate = new Date(0L); // used in noTimestamp warning
162
163 // Severe warnings
164 private int weakAlg = 0; // 1. digestalg, 2. sigalg, 4. tsadigestalg
165 private boolean hasExpiredCert = false;
166 private boolean notYetValidCert = false;
167 private boolean chainNotValidated = false;
168 private boolean notSignedByAlias = false;
169 private boolean aliasNotInStore = false;
170 private boolean hasUnsignedEntry = false;
171 private boolean badKeyUsage = false;
172 private boolean badExtendedKeyUsage = false;
173 private boolean badNetscapeCertType = false;
174 private boolean signerSelfSigned = false;
175
176 private Throwable chainNotValidatedReason = null;
177
178 private boolean seeWeak = false;
179
180 CertificateFactory certificateFactory;
181 CertPathValidator validator;
182 PKIXParameters pkixParameters;
183
184 public void run(String args[]) {
185 try {
186 args = parseArgs(args);
187
188 // Try to load and install the specified providers
189 if (providers != null) {
190 for (String provName: providers) {
191 try {
192 KeyStoreUtil.loadProviderByName(provName,
193 providerArgs.get(provName));
194 if (debug) {
195 System.out.println("loadProviderByName: " + provName);
196 }
197 } catch (IllegalArgumentException e) {
198 throw new Exception(String.format(rb.getString(
199 "provider.name.not.found"), provName));
625 System.out.println(rb.getString
626 (".providerClass.option"));
627 System.out.println(rb.getString
628 (".providerArg.option.2"));
629 System.out.println();
630 System.out.println(rb.getString
631 (".strict.treat.warnings.as.errors"));
632 System.out.println();
633 System.out.println(rb.getString
634 (".conf.url.specify.a.pre.configured.options.file"));
635 System.out.println();
636
637 System.exit(0);
638 }
639
640 void verifyJar(String jarName)
641 throws Exception
642 {
643 boolean anySigned = false; // if there exists entry inside jar signed
644 JarFile jf = null;
645 Map<String,String> digestMap = new HashMap<>();
646 Map<String,PKCS7> sigMap = new HashMap<>();
647 Map<String,String> sigNameMap = new HashMap<>();
648 Map<String,String> unparsableSignatures = new HashMap<>();
649
650 try {
651 jf = new JarFile(jarName, true);
652 Vector<JarEntry> entriesVec = new Vector<>();
653 byte[] buffer = new byte[8192];
654
655 Enumeration<JarEntry> entries = jf.entries();
656 while (entries.hasMoreElements()) {
657 JarEntry je = entries.nextElement();
658 entriesVec.addElement(je);
659 try (InputStream is = jf.getInputStream(je)) {
660 String name = je.getName();
661 if (signatureRelated(name)
662 && SignatureFileVerifier.isBlockOrSF(name)) {
663 String alias = name.substring(name.lastIndexOf('/') + 1,
664 name.lastIndexOf('.'));
665 try {
666 if (name.endsWith(".SF")) {
667 Manifest sf = new Manifest(is);
668 boolean found = false;
669 for (Object obj : sf.getMainAttributes().keySet()) {
670 String key = obj.toString();
671 if (key.endsWith("-Digest-Manifest")) {
672 digestMap.put(alias,
673 key.substring(0, key.length() - 16));
674 found = true;
675 break;
676 }
677 }
678 if (!found) {
679 unparsableSignatures.putIfAbsent(alias,
680 String.format(
681 rb.getString("history.unparsable"),
682 name));
683 }
684 } else {
685 sigNameMap.put(alias, name);
686 sigMap.put(alias, new PKCS7(is));
687 }
688 } catch (IOException ioe) {
689 unparsableSignatures.putIfAbsent(alias, String.format(
690 rb.getString("history.unparsable"), name));
691 }
692 } else {
693 while (is.read(buffer, 0, buffer.length) != -1) {
694 // we just read. this will throw a SecurityException
695 // if a signature/digest check fails.
696 }
697 }
698 }
699 }
700
701 Manifest man = jf.getManifest();
702 boolean hasSignature = false;
703
704 // The map to record display info, only used when -verbose provided
705 // key: signer info string
706 // value: the list of files with common key
707 Map<String,List<String>> output = new LinkedHashMap<>();
708
709 if (man != null) {
710 if (verbose != null) System.out.println();
711 Enumeration<JarEntry> e = entriesVec.elements();
712
713 String tab = rb.getString("6SPACE");
714
715 while (e.hasMoreElements()) {
716 JarEntry je = e.nextElement();
834 String.format(rb.getString(
835 ".and.d.more."), files.size()-1));
836 } else {
837 System.out.println(files.get(0));
838 }
839 }
840 System.out.printf(key.substring(pipe+1));
841 }
842 }
843 System.out.println();
844 System.out.println(rb.getString(
845 ".s.signature.was.verified."));
846 System.out.println(rb.getString(
847 ".m.entry.is.listed.in.manifest"));
848 System.out.println(rb.getString(
849 ".k.at.least.one.certificate.was.found.in.keystore"));
850 if (ckaliases.size() > 0) {
851 System.out.println(rb.getString(
852 ".X.not.signed.by.specified.alias.es."));
853 }
854 }
855 if (man == null) {
856 System.out.println();
857 System.out.println(rb.getString("no.manifest."));
858 }
859
860 // If signer is a trusted cert or private entry in user's own
861 // keystore, it can be self-signed.
862 if (!aliasNotInStore) {
863 signerSelfSigned = false;
864 }
865
866 // Even if the verbose option is not specified, all out strings
867 // must be generated so seeWeak can be updated.
868 if (!digestMap.isEmpty()
869 || !sigMap.isEmpty()
870 || !unparsableSignatures.isEmpty()) {
871 if (verbose != null) {
872 System.out.println();
873 }
874 for (String s : sigMap.keySet()) {
875 if (!digestMap.containsKey(s)) {
876 unparsableSignatures.putIfAbsent(s, String.format(
877 rb.getString("history.nosf"), s));
878 }
879 }
880 for (String s : digestMap.keySet()) {
881 PKCS7 p7 = sigMap.get(s);
882 if (p7 != null) {
883 String history;
884 try {
885 SignerInfo si = p7.getSignerInfos()[0];
886 X509Certificate signer = si.getCertificate(p7);
887 String digestAlg = digestMap.get(s);
888 String sigAlg = AlgorithmId.makeSigAlg(
889 si.getDigestAlgorithmId().getName(),
890 si.getDigestEncryptionAlgorithmId().getName());
891 PublicKey key = signer.getPublicKey();
892 PKCS7 tsToken = si.getTsToken();
893 if (tsToken != null) {
894 SignerInfo tsSi = tsToken.getSignerInfos()[0];
895 X509Certificate tsSigner = tsSi.getCertificate(tsToken);
896 byte[] encTsTokenInfo = tsToken.getContentInfo().getData();
897 TimestampToken tsTokenInfo = new TimestampToken(encTsTokenInfo);
898 PublicKey tsKey = tsSigner.getPublicKey();
899 String tsDigestAlg = tsTokenInfo.getHashAlgorithm().getName();
900 String tsSigAlg = AlgorithmId.makeSigAlg(
901 tsSi.getDigestAlgorithmId().getName(),
902 tsSi.getDigestEncryptionAlgorithmId().getName());
903 Calendar c = Calendar.getInstance(
904 TimeZone.getTimeZone("UTC"),
905 Locale.getDefault(Locale.Category.FORMAT));
906 c.setTime(tsTokenInfo.getDate());
907 history = String.format(
908 rb.getString("history.with.ts"),
909 signer.getSubjectX500Principal(),
910 withWeak(digestAlg, DIGEST_PRIMITIVE_SET),
911 withWeak(sigAlg, SIG_PRIMITIVE_SET),
912 withWeak(key),
913 c,
914 tsSigner.getSubjectX500Principal(),
915 withWeak(tsDigestAlg, DIGEST_PRIMITIVE_SET),
916 withWeak(tsSigAlg, SIG_PRIMITIVE_SET),
917 withWeak(tsKey));
918 } else {
919 history = String.format(
920 rb.getString("history.without.ts"),
921 signer.getSubjectX500Principal(),
922 withWeak(digestAlg, DIGEST_PRIMITIVE_SET),
923 withWeak(sigAlg, SIG_PRIMITIVE_SET),
924 withWeak(key));
925 }
926 } catch (Exception e) {
927 // The only usage of sigNameMap, remember the name
928 // of the block file if it's invalid.
929 history = String.format(
930 rb.getString("history.unparsable"),
931 sigNameMap.get(s));
932 }
933 if (verbose != null) {
934 System.out.println(history);
935 }
936 } else {
937 unparsableSignatures.putIfAbsent(s, String.format(
938 rb.getString("history.nobk"), s));
939 }
940 }
941 if (verbose != null) {
942 for (String s : unparsableSignatures.keySet()) {
943 System.out.println(unparsableSignatures.get(s));
944 }
945 }
946 }
947 System.out.println();
948 if (!anySigned) {
949 if (seeWeak) {
950 if (verbose != null) {
951 System.out.println(rb.getString("jar.treated.unsigned.see.weak.verbose"));
952 System.out.println("\n " +
953 DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS +
954 "=" + Security.getProperty(DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS));
955 } else {
956 System.out.println(rb.getString("jar.treated.unsigned.see.weak"));
957 }
958 } else if (hasSignature) {
959 System.out.println(rb.getString("jar.treated.unsigned"));
960 } else {
961 System.out.println(rb.getString("jar.is.unsigned"));
962 }
963 } else {
964 boolean warningAppeared = false;
965 boolean errorAppeared = false;
966 if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
967 notYetValidCert || chainNotValidated || hasExpiredCert ||
968 hasUnsignedEntry || signerSelfSigned || (weakAlg != 0) ||
969 aliasNotInStore || notSignedByAlias) {
970
971 if (strict) {
972 System.out.println(rb.getString("jar.verified.with.signer.errors."));
973 System.out.println();
974 System.out.println(rb.getString("Error."));
975 errorAppeared = true;
976 } else {
977 System.out.println(rb.getString("jar.verified."));
978 System.out.println();
979 System.out.println(rb.getString("Warning."));
980 warningAppeared = true;
981 }
982
983 if (weakAlg != 0) {
984 // In fact, jarsigner verification did not catch this
985 // since it has not read the JarFile content itself.
986 // Everything is done with JarFile API. The signing
987 // history (digestMap etc) will show these info and
988 // print out proper warnings.
989 }
990
991 if (badKeyUsage) {
992 System.out.println(
993 rb.getString("This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));
994 }
995
996 if (badExtendedKeyUsage) {
997 System.out.println(
998 rb.getString("This.jar.contains.entries.whose.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."));
999 }
1000
1001 if (badNetscapeCertType) {
1002 System.out.println(
1003 rb.getString("This.jar.contains.entries.whose.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."));
1004 }
1005
1006 if (hasUnsignedEntry) {
1007 System.out.println(rb.getString(
1008 "This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked."));
1059 System.out.println(rb.getString(
1060 "Re.run.with.the.verbose.and.certs.options.for.more.details."));
1061 }
1062 }
1063 }
1064 return;
1065 } catch (Exception e) {
1066 System.out.println(rb.getString("jarsigner.") + e);
1067 if (debug) {
1068 e.printStackTrace();
1069 }
1070 } finally { // close the resource
1071 if (jf != null) {
1072 jf.close();
1073 }
1074 }
1075
1076 System.exit(1);
1077 }
1078
1079 private String withWeak(String alg, Set<CryptoPrimitive> primitiveSet) {
1080 if (DISABLED_CHECK.permits(primitiveSet, alg, null)) {
1081 return alg;
1082 } else {
1083 seeWeak = true;
1084 return String.format(rb.getString("with.weak"), alg);
1085 }
1086 }
1087
1088 private String withWeak(PublicKey key) {
1089 if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
1090 return String.format(
1091 rb.getString("key.bit"), KeyUtil.getKeySize(key));
1092 } else {
1093 seeWeak = true;
1094 return String.format(
1095 rb.getString("key.bit.weak"), KeyUtil.getKeySize(key));
1096 }
1097 }
1098
1099 private static MessageFormat validityTimeForm = null;
1100 private static MessageFormat notYetTimeForm = null;
1101 private static MessageFormat expiredTimeForm = null;
1102 private static MessageFormat expiringTimeForm = null;
1103
1104 /*
1105 * Display some details about a certificate:
1106 *
1107 * [<tab>] <cert-type> [", " <subject-DN>] [" (" <keystore-entry-alias> ")"]
1108 * [<validity-period> | <expiry-warning>]
1109 *
1110 * Note: no newline character at the end
1111 */
1112 String printCert(String tab, Certificate c, boolean checkValidityPeriod,
1113 Date timestamp, boolean checkUsage) {
1114
1115 StringBuilder certStr = new StringBuilder();
1116 String space = rb.getString("SPACE");
1117 X509Certificate x509Cert = null;
1118
1268 int inKeyStore(CodeSigner[] signers) {
1269
1270 if (signers == null)
1271 return 0;
1272
1273 int output = 0;
1274
1275 for (CodeSigner signer: signers) {
1276 int result = inKeyStoreForOneSigner(signer);
1277 output |= result;
1278 }
1279 if (ckaliases.size() > 0 && (output & SIGNED_BY_ALIAS) == 0) {
1280 output |= NOT_ALIAS;
1281 }
1282 return output;
1283 }
1284
1285 void signJar(String jarName, String alias)
1286 throws Exception {
1287
1288 if (digestalg != null && !DISABLED_CHECK.permits(
1289 DIGEST_PRIMITIVE_SET, digestalg, null)) {
1290 weakAlg |= 1;
1291 }
1292 if (tSADigestAlg != null && !DISABLED_CHECK.permits(
1293 DIGEST_PRIMITIVE_SET, tSADigestAlg, null)) {
1294 weakAlg |= 4;
1295 }
1296 if (sigalg != null && !DISABLED_CHECK.permits(
1297 SIG_PRIMITIVE_SET , sigalg, null)) {
1298 weakAlg |= 2;
1299 }
1300 if (!DISABLED_CHECK.permits(
1301 SIG_PRIMITIVE_SET, privateKey)) {
1302 weakAlg |= 8;
1303 }
1304
1305 boolean aliasUsed = false;
1306 X509Certificate tsaCert = null;
1307
1308 if (sigfile == null) {
1309 sigfile = alias;
1310 aliasUsed = true;
1311 }
1312
1313 if (sigfile.length() > 8) {
1314 sigfile = sigfile.substring(0, 8).toUpperCase(Locale.ENGLISH);
1315 } else {
1316 sigfile = sigfile.toUpperCase(Locale.ENGLISH);
1317 }
1318
1319 StringBuilder tmpSigFile = new StringBuilder(sigfile.length());
1320 for (int j = 0; j < sigfile.length(); j++) {
1321 char c = sigfile.charAt(j);
1322 if (!
1323 ((c>= 'A' && c<= 'Z') ||
1528 System.out.println(
1529 rb.getString("The.signer.s.certificate.is.self.signed."));
1530 }
1531
1532 if ((weakAlg & 1) == 1) {
1533 System.out.println(String.format(
1534 rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
1535 digestalg, "-digestalg"));
1536 }
1537
1538 if ((weakAlg & 2) == 2) {
1539 System.out.println(String.format(
1540 rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
1541 sigalg, "-sigalg"));
1542 }
1543 if ((weakAlg & 4) == 4) {
1544 System.out.println(String.format(
1545 rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
1546 tSADigestAlg, "-tsadigestalg"));
1547 }
1548 if ((weakAlg & 8) == 8) {
1549 System.out.println(String.format(
1550 rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk."),
1551 privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey)));
1552 }
1553 } else {
1554 System.out.println(rb.getString("jar.signed."));
1555 }
1556 if (hasExpiringCert || noTimestamp) {
1557 if (!warningAppeared) {
1558 System.out.println();
1559 System.out.println(rb.getString("Warning."));
1560 }
1561
1562 if (hasExpiringCert) {
1563 System.out.println(
1564 rb.getString("The.signer.certificate.will.expire.within.six.months."));
1565 }
1566
1567 if (noTimestamp) {
1568 System.out.println(
1569 String.format(rb.getString("no.timestamp.signing"), expireDate));
1570 }
1571 }
1572
|