< prev index next >

src/share/classes/sun/security/pkcs/SignerInfo.java

Print this page
rev 1455 : 6870812: enhance security tools to use ECC algorithms
Reviewed-by: vinnie, mullan
rev 1462 : 7180907: Jarsigner -verify fails if rsa file used sha-256 with authenticated attributes
Reviewed-by: xuelei, vinnie
rev 1514 : 8049480: Current versions of Java can't verify jars signed and timestamped with Java 9
Reviewed-by: xuelei, mullan
rev 1518 : 7102686: Restructure timestamp code so that jars and modules can more easily share the same code
Reviewed-by: mchung
rev 1547 : 8155973: Tighten jar checks
Reviewed-by: mullan, igerasim, ahgross
rev 1590 : 8165816: jarsigner -verify shows jar unsigned if it was signed with a weak algorithm
Reviewed-by: mullan

*** 1,7 **** /* ! * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this --- 1,7 ---- /* ! * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this
*** 26,58 **** package sun.security.pkcs; import java.io.OutputStream; import java.io.IOException; import java.math.BigInteger; import java.security.cert.X509Certificate; - import java.security.*; import java.util.ArrayList; ! import sun.security.util.*; import sun.security.x509.AlgorithmId; import sun.security.x509.X500Name; import sun.security.x509.KeyUsageExtension; - import sun.misc.HexDumpEncoder; /** * A SignerInfo, as defined in PKCS#7's signedData type. * * @author Benjamin Renaud */ public class SignerInfo implements DerEncoder { BigInteger version; X500Name issuerName; BigInteger certificateSerialNumber; AlgorithmId digestAlgorithmId; AlgorithmId digestEncryptionAlgorithmId; byte[] encryptedDigest; PKCS9Attributes authenticatedAttributes; PKCS9Attributes unauthenticatedAttributes; public SignerInfo(X500Name issuerName, --- 26,95 ---- package sun.security.pkcs; import java.io.OutputStream; import java.io.IOException; import java.math.BigInteger; + import java.security.InvalidKeyException; + import java.security.MessageDigest; + import java.security.NoSuchAlgorithmException; + import java.security.Principal; + import java.security.PublicKey; + import java.security.Signature; + import java.security.SignatureException; + import java.security.Timestamp; + import java.security.cert.CertificateException; + import java.security.cert.CertificateFactory; + import java.security.cert.CertPath; import java.security.cert.X509Certificate; import java.util.ArrayList; + import java.util.Arrays; + import java.util.Collections; + import java.util.EnumSet; + import java.util.Set; ! import sun.misc.HexDumpEncoder; ! import sun.security.timestamp.TimestampToken; ! import sun.security.util.CryptoPrimitive; ! import sun.security.util.Debug; ! import sun.security.util.DerEncoder; ! import sun.security.util.DerInputStream; ! import sun.security.util.DerOutputStream; ! import sun.security.util.DerValue; ! import sun.security.util.DisabledAlgorithmConstraints; ! import sun.security.util.KeyUtil; ! import sun.security.util.ObjectIdentifier; import sun.security.x509.AlgorithmId; import sun.security.x509.X500Name; import sun.security.x509.KeyUsageExtension; /** * A SignerInfo, as defined in PKCS#7's signedData type. * * @author Benjamin Renaud */ public class SignerInfo implements DerEncoder { + // Digest and Signature restrictions + private static final Set<CryptoPrimitive> DIGEST_PRIMITIVE_SET = + Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST)); + + private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET = + Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); + + private static final DisabledAlgorithmConstraints JAR_DISABLED_CHECK = + new DisabledAlgorithmConstraints( + DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS); + BigInteger version; X500Name issuerName; BigInteger certificateSerialNumber; AlgorithmId digestAlgorithmId; AlgorithmId digestEncryptionAlgorithmId; byte[] encryptedDigest; + Timestamp timestamp; + private boolean hasTimestamp = true; + private static final Debug debug = Debug.getInstance("jar"); PKCS9Attributes authenticatedAttributes; PKCS9Attributes unauthenticatedAttributes; public SignerInfo(X500Name issuerName,
*** 283,294 **** if (data == null) { data = content.getContentBytes(); } String digestAlgname = getDigestAlgorithmId().getName(); - if (digestAlgname.equalsIgnoreCase("SHA")) - digestAlgname = "SHA1"; byte[] dataSigned; // if there are authenticate attributes, get the message // digest and compare it with the digest of data --- 320,329 ----
*** 310,320 **** PKCS9Attribute.MESSAGE_DIGEST_OID); if (messageDigest == null) // fail if there is no message digest return null; ! MessageDigest md = MessageDigest.getInstance(digestAlgname); byte[] computedMessageDigest = md.digest(data); if (messageDigest.length != computedMessageDigest.length) return null; for (int i = 0; i < messageDigest.length; i++) { --- 345,363 ---- PKCS9Attribute.MESSAGE_DIGEST_OID); if (messageDigest == null) // fail if there is no message digest return null; ! // check that algorithm is not restricted ! if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET, ! digestAlgname, null)) { ! throw new SignatureException("Digest check failed. " + ! "Disabled algorithm used: " + digestAlgname); ! } ! ! MessageDigest md = MessageDigest.getInstance( ! AlgorithmId.getStandardDigestName(digestAlgname)); byte[] computedMessageDigest = md.digest(data); if (messageDigest.length != computedMessageDigest.length) return null; for (int i = 0; i < messageDigest.length; i++) {
*** 334,353 **** // put together digest algorithm and encryption algorithm // to form signing algorithm String encryptionAlgname = getDigestEncryptionAlgorithmId().getName(); ! if (encryptionAlgname.equalsIgnoreCase("SHA1withDSA")) ! encryptionAlgname = "DSA"; ! String algname = digestAlgname + "with" + encryptionAlgname; - Signature sig = Signature.getInstance(algname); X509Certificate cert = getCertificate(block); ! if (cert == null) { return null; } if (cert.hasUnsupportedCriticalExtension()) { throw new SignatureException("Certificate has unsupported " + "critical extension(s)"); } --- 377,413 ---- // put together digest algorithm and encryption algorithm // to form signing algorithm String encryptionAlgname = getDigestEncryptionAlgorithmId().getName(); ! // Workaround: sometimes the encryptionAlgname is actually ! // a signature name ! String tmp = AlgorithmId.getEncAlgFromSigAlg(encryptionAlgname); ! if (tmp != null) encryptionAlgname = tmp; ! String algname = AlgorithmId.makeSigAlg( ! digestAlgname, encryptionAlgname); ! ! // check that algorithm is not restricted ! if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, algname, null)) { ! throw new SignatureException("Signature check failed. " + ! "Disabled algorithm used: " + algname); ! } X509Certificate cert = getCertificate(block); ! PublicKey key = cert.getPublicKey(); if (cert == null) { return null; } + + // check if the public key is restricted + if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) { + throw new SignatureException("Public key check failed. " + + "Disabled key used: " + + KeyUtil.getKeySize(key) + " bit " + + key.getAlgorithm()); + } + if (cert.hasUnsupportedCriticalExtension()) { throw new SignatureException("Certificate has unsupported " + "critical extension(s)"); }
*** 380,394 **** + "cannot be used for " + "digital signatures"); } } ! PublicKey key = cert.getPublicKey(); sig.initVerify(key); - sig.update(dataSigned); - if (sig.verify(encryptedDigest)) { return this; } } catch (IOException e) { --- 440,452 ---- + "cannot be used for " + "digital signatures"); } } ! Signature sig = Signature.getInstance(algname); sig.initVerify(key); sig.update(dataSigned); if (sig.verify(encryptedDigest)) { return this; } } catch (IOException e) {
*** 439,448 **** --- 497,599 ---- public PKCS9Attributes getUnauthenticatedAttributes() { return unauthenticatedAttributes; } + /* + * Extracts a timestamp from a PKCS7 SignerInfo. + * + * Examines the signer's unsigned attributes for a + * <tt>signatureTimestampToken</tt> attribute. If present, + * then it is parsed to extract the date and time at which the + * timestamp was generated. + * + * @param info A signer information element of a PKCS 7 block. + * + * @return A timestamp token or null if none is present. + * @throws IOException if an error is encountered while parsing the + * PKCS7 data. + * @throws NoSuchAlgorithmException if an error is encountered while + * verifying the PKCS7 object. + * @throws SignatureException if an error is encountered while + * verifying the PKCS7 object. + * @throws CertificateException if an error is encountered while generating + * the TSA's certpath. + */ + public Timestamp getTimestamp() + throws IOException, NoSuchAlgorithmException, SignatureException, + CertificateException + { + if (timestamp != null || !hasTimestamp) + return timestamp; + + if (unauthenticatedAttributes == null) { + hasTimestamp = false; + return null; + } + PKCS9Attribute tsTokenAttr = + unauthenticatedAttributes.getAttribute( + PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_OID); + if (tsTokenAttr == null) { + hasTimestamp = false; + return null; + } + + PKCS7 tsToken = new PKCS7((byte[])tsTokenAttr.getValue()); + // Extract the content (an encoded timestamp token info) + byte[] encTsTokenInfo = tsToken.getContentInfo().getData(); + // Extract the signer (the Timestamping Authority) + // while verifying the content + SignerInfo[] tsa = tsToken.verify(encTsTokenInfo); + // Expect only one signer + ArrayList<X509Certificate> chain = tsa[0].getCertificateChain(tsToken); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + CertPath tsaChain = cf.generateCertPath(chain); + // Create a timestamp token info object + TimestampToken tsTokenInfo = new TimestampToken(encTsTokenInfo); + // Check that the signature timestamp applies to this signature + verifyTimestamp(tsTokenInfo); + // Create a timestamp object + timestamp = new Timestamp(tsTokenInfo.getDate(), tsaChain); + return timestamp; + } + + /* + * Check that the signature timestamp applies to this signature. + * Match the hash present in the signature timestamp token against the hash + * of this signature. + */ + private void verifyTimestamp(TimestampToken token) + throws NoSuchAlgorithmException, SignatureException { + String digestAlgname = + AlgorithmId.getStandardDigestName(token.getHashAlgorithm().getName()); + // check that algorithm is not restricted + if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET, digestAlgname, + null)) { + throw new SignatureException("Timestamp token digest check failed. " + + "Disabled algorithm used: " + digestAlgname); + } + + MessageDigest md = + MessageDigest.getInstance(digestAlgname); + + if (!Arrays.equals(token.getHashedMessage(), + md.digest(encryptedDigest))) { + + throw new SignatureException("Signature timestamp (#" + + token.getSerialNumber() + ") generated on " + token.getDate() + + " is inapplicable"); + } + + if (debug != null) { + debug.println(); + debug.println("Detected signature timestamp (#" + + token.getSerialNumber() + ") generated on " + token.getDate()); + debug.println(); + } + } + public String toString() { HexDumpEncoder hexDump = new HexDumpEncoder(); String out = "";
*** 464,470 **** out += "\tunauthenticatedAttributes: " + unauthenticatedAttributes + "\n"; } return out; } - } --- 615,620 ----
< prev index next >