8242068: Signed JAR support for RSASSA-PSS and EdDSA

Reviewed-by: valeriep
This commit is contained in:
Weijun Wang 2020-10-21 14:18:43 +00:00
parent e559bd2c8b
commit 839f01ddf5
24 changed files with 1311 additions and 737 deletions

View File

@ -196,8 +196,8 @@ public class ContentInfo {
if (content == null)
return null;
DerInputStream dis = new DerInputStream(content.toByteArray());
return dis.getOctetString();
DerValue v = new DerValue(content.toByteArray());
return v.getOctetString();
}
public String toString() {

View File

@ -28,6 +28,9 @@ package sun.security.pkcs;
import java.io.*;
import java.math.BigInteger;
import java.net.URI;
import java.security.interfaces.EdECPrivateKey;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.PSSParameterSpec;
import java.util.*;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
@ -35,14 +38,12 @@ import java.security.cert.X509CRL;
import java.security.cert.CRLException;
import java.security.cert.CertificateFactory;
import java.security.*;
import java.util.function.Function;
import sun.security.provider.SHAKE256;
import sun.security.timestamp.*;
import sun.security.util.*;
import sun.security.x509.AlgorithmId;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;
import sun.security.x509.X509CRLImpl;
import sun.security.x509.X500Name;
import sun.security.x509.*;
/**
* PKCS7 as defined in RSA Laboratories PKCS7 Technical Note. Profile
@ -86,16 +87,6 @@ public class PKCS7 {
}
}
/*
* Object identifier for the timestamping key purpose.
*/
private static final String KP_TIMESTAMPING_OID = "1.3.6.1.5.5.7.3.8";
/*
* Object identifier for extendedKeyUsage extension
*/
private static final String EXTENDED_KEY_USAGE_OID = "2.5.29.37";
/**
* Unmarshals a PKCS7 block from its encoded form, parsing the
* encoded bytes from the InputStream.
@ -178,9 +169,9 @@ public class PKCS7 {
private void parse(DerInputStream derin, boolean oldStyle)
throws IOException
{
contentInfo = new ContentInfo(derin, oldStyle);
contentType = contentInfo.contentType;
DerValue content = contentInfo.getContent();
ContentInfo block = new ContentInfo(derin, oldStyle);
contentType = block.contentType;
DerValue content = block.getContent();
if (contentType.equals(ContentInfo.SIGNED_DATA_OID)) {
parseSignedData(content);
@ -189,6 +180,7 @@ public class PKCS7 {
parseOldSignedData(content);
} else if (contentType.equals(ContentInfo.NETSCAPE_CERT_SEQUENCE_OID)){
parseNetscapeCertChain(content);
contentInfo = block; // Maybe useless, just do not let it be null
} else {
throw new ParsingException("content type " + contentType +
" not supported.");
@ -773,6 +765,128 @@ public class PKCS7 {
return this.oldStyle;
}
/**
* Generate a PKCS7 data block.
*
* @param sigalg signature algorithm to be used
* @param sigProvider (optional) provider
* @param privateKey signer's private ky
* @param signerChain signer's certificate chain
* @param content the content to sign
* @param internalsf whether the content should be include in output
* @param directsign if the content is signed directly or thru authattrs
* @param ts (optional) timestamper
* @return the pkcs7 output in an array
* @throws SignatureException if signing failed
* @throws InvalidKeyException if key cannot be used
* @throws IOException should not happen here, all byte array
* @throws NoSuchAlgorithmException if siglag is bad
*/
public static byte[] generateNewSignedData(
String sigalg, Provider sigProvider,
PrivateKey privateKey, X509Certificate[] signerChain,
byte[] content, boolean internalsf, boolean directsign,
Function<byte[], PKCS9Attributes> ts)
throws SignatureException, InvalidKeyException, IOException,
NoSuchAlgorithmException {
Signature signer = SignatureUtil.fromKey(sigalg, privateKey, sigProvider);
AlgorithmId digAlgID = SignatureUtil.getDigestAlgInPkcs7SignerInfo(
signer, sigalg, privateKey, directsign);
AlgorithmId sigAlgID = SignatureUtil.fromSignature(signer, privateKey);
PKCS9Attributes authAttrs = null;
if (!directsign) {
// MessageDigest
byte[] md;
String digAlgName = digAlgID.getName();
if (digAlgName.equals("SHAKE256") || digAlgName.equals("SHAKE256-LEN")) {
// No MessageDigest impl for SHAKE256 yet
var shaker = new SHAKE256(64);
shaker.update(content, 0, content.length);
md = shaker.digest();
} else {
md = MessageDigest.getInstance(digAlgName)
.digest(content);
}
// CMSAlgorithmProtection (RFC6211)
DerOutputStream derAp = new DerOutputStream();
DerOutputStream derAlgs = new DerOutputStream();
digAlgID.derEncode(derAlgs);
DerOutputStream derSigAlg = new DerOutputStream();
sigAlgID.derEncode(derSigAlg);
derAlgs.writeImplicit((byte)0xA1, derSigAlg);
derAp.write(DerValue.tag_Sequence, derAlgs);
authAttrs = new PKCS9Attributes(new PKCS9Attribute[]{
new PKCS9Attribute(PKCS9Attribute.CONTENT_TYPE_OID,
ContentInfo.DATA_OID),
new PKCS9Attribute(PKCS9Attribute.SIGNING_TIME_OID,
new Date()),
new PKCS9Attribute(PKCS9Attribute.CMS_ALGORITHM_PROTECTION_OID,
derAp.toByteArray()),
new PKCS9Attribute(PKCS9Attribute.MESSAGE_DIGEST_OID,
md)
});
signer.update(authAttrs.getDerEncoding());
} else {
signer.update(content);
}
byte[] signature = signer.sign();
return constructToken(signature, signerChain,
internalsf ? content : null,
authAttrs,
ts == null ? null : ts.apply(signature),
digAlgID,
sigAlgID);
}
/**
* Assemble a PKCS7 token from its components
* @param signature the signature
* @param signerChain the signer's certificate chain
* @param content (optional) encapsulated content
* @param authAttrs (optional) authenticated attributes
* @param unauthAttrs (optional) unauthenticated attributes
* @param digAlgID digest algorithm identifier
* @param encAlgID encryption algorithm identifier
* @return the token in a byte array
* @throws IOException should not happen here, all byte array
*/
private static byte[] constructToken(byte[] signature,
X509Certificate[] signerChain,
byte[] content,
PKCS9Attributes authAttrs,
PKCS9Attributes unauthAttrs,
AlgorithmId digAlgID,
AlgorithmId encAlgID)
throws IOException {
// Create the SignerInfo
X500Name issuerName =
X500Name.asX500Name(signerChain[0].getIssuerX500Principal());
BigInteger serialNumber = signerChain[0].getSerialNumber();
SignerInfo signerInfo = new SignerInfo(issuerName, serialNumber,
digAlgID, authAttrs,
encAlgID,
signature, unauthAttrs);
// Create the PKCS #7 signed data message
SignerInfo[] signerInfos = {signerInfo};
AlgorithmId[] algorithms = {signerInfo.getDigestAlgorithmId()};
// Include or exclude content
ContentInfo contentInfo = (content == null)
? new ContentInfo(ContentInfo.DATA_OID, null)
: new ContentInfo(content);
PKCS7 pkcs7 = new PKCS7(algorithms, contentInfo,
signerChain, signerInfos);
ByteArrayOutputStream p7out = new ByteArrayOutputStream();
pkcs7.encodeSignedData(p7out);
return p7out.toByteArray();
}
/**
* Assembles a PKCS #7 signed data message that optionally includes a
* signature timestamp.
@ -797,6 +911,7 @@ public class PKCS7 {
* generating the signature timestamp or while generating the signed
* data message.
*/
@Deprecated(since="16", forRemoval=true)
public static byte[] generateSignedData(byte[] signature,
X509Certificate[] signerChain,
byte[] content,
@ -824,34 +939,59 @@ public class PKCS7 {
tsToken)});
}
// Create the SignerInfo
X500Name issuerName =
X500Name.asX500Name(signerChain[0].getIssuerX500Principal());
BigInteger serialNumber = signerChain[0].getSerialNumber();
String encAlg = AlgorithmId.getEncAlgFromSigAlg(signatureAlgorithm);
String digAlg = AlgorithmId.getDigAlgFromSigAlg(signatureAlgorithm);
if (digAlg == null) {
throw new UnsupportedOperationException("Unable to determine " +
"the digest algorithm from the signature algorithm.");
return constructToken(signature, signerChain, content,
null,
unauthAttrs,
AlgorithmId.get(SignatureUtil.extractDigestAlgFromDwithE(signatureAlgorithm)),
AlgorithmId.get(signatureAlgorithm));
}
/**
* Examine the certificate for a Subject Information Access extension
* (<a href="http://tools.ietf.org/html/rfc5280">RFC 5280</a>).
* The extension's {@code accessMethod} field should contain the object
* identifier defined for timestamping: 1.3.6.1.5.5.7.48.3 and its
* {@code accessLocation} field should contain an HTTP or HTTPS URL.
*
* @param tsaCertificate (optional) X.509 certificate for the TSA.
* @return An HTTP or HTTPS URI or null if none was found.
*/
public static URI getTimestampingURI(X509Certificate tsaCertificate) {
if (tsaCertificate == null) {
return null;
}
SignerInfo signerInfo = new SignerInfo(issuerName, serialNumber,
AlgorithmId.get(digAlg), null,
AlgorithmId.get(encAlg),
signature, unauthAttrs);
// Create the PKCS #7 signed data message
SignerInfo[] signerInfos = {signerInfo};
AlgorithmId[] algorithms = {signerInfo.getDigestAlgorithmId()};
// Include or exclude content
ContentInfo contentInfo = (content == null)
? new ContentInfo(ContentInfo.DATA_OID, null)
: new ContentInfo(content);
PKCS7 pkcs7 = new PKCS7(algorithms, contentInfo,
signerChain, signerInfos);
ByteArrayOutputStream p7out = new ByteArrayOutputStream();
pkcs7.encodeSignedData(p7out);
return p7out.toByteArray();
// Parse the extensions
try {
byte[] extensionValue = tsaCertificate.getExtensionValue
(KnownOIDs.SubjectInfoAccess.value());
if (extensionValue == null) {
return null;
}
DerInputStream der = new DerInputStream(extensionValue);
der = new DerInputStream(der.getOctetString());
DerValue[] derValue = der.getSequence(5);
AccessDescription description;
GeneralName location;
URIName uri;
for (int i = 0; i < derValue.length; i++) {
description = new AccessDescription(derValue[i]);
if (description.getAccessMethod()
.equals(ObjectIdentifier.of(KnownOIDs.AD_TimeStamping))) {
location = description.getAccessLocation();
if (location.getType() == GeneralNameInterface.NAME_URI) {
uri = (URIName) location.getName();
if (uri.getScheme().equalsIgnoreCase("http") ||
uri.getScheme().equalsIgnoreCase("https")) {
return uri.getURI();
}
}
}
}
} catch (IOException ioe) {
// ignore
}
return null;
}
/**
@ -873,7 +1013,7 @@ public class PKCS7 {
* @throws CertificateException The exception is thrown if the TSA's
* certificate is not permitted for timestamping.
*/
private static byte[] generateTimestampToken(Timestamper tsa,
public static byte[] generateTimestampToken(Timestamper tsa,
String tSAPolicyID,
String tSADigestAlg,
byte[] toBeTimestamped)
@ -944,13 +1084,13 @@ public class PKCS7 {
"Certificate not included in timestamp token");
} else {
if (!cert.getCriticalExtensionOIDs().contains(
EXTENDED_KEY_USAGE_OID)) {
KnownOIDs.extendedKeyUsage.value())) {
throw new CertificateException(
"Certificate is not valid for timestamping");
}
List<String> keyPurposes = cert.getExtendedKeyUsage();
if (keyPurposes == null ||
!keyPurposes.contains(KP_TIMESTAMPING_OID)) {
!keyPurposes.contains(KnownOIDs.KP_TimeStamping.value())) {
throw new CertificateException(
"Certificate is not valid for timestamping");
}

View File

@ -164,6 +164,13 @@ import sun.security.util.*;
* <TD>byte[]</TD>
* </TR>
*
* <TR>
* <TD>1.2.840.113549.1.9.16.2.52</TD>
* <TD>CMSAlgorithmProtection</TD>
* <TD>Single-valued</TD>
* <TD>byte[]</TD>
* </TR>
*
* </TABLE>
*
* @author Douglas Hoover
@ -176,7 +183,7 @@ public class PKCS9Attribute implements DerEncoder {
/**
* Array of attribute OIDs defined in PKCS9, by number.
*/
static final ObjectIdentifier[] PKCS9_OIDS = new ObjectIdentifier[18];
static final ObjectIdentifier[] PKCS9_OIDS = new ObjectIdentifier[19];
private static final Class<?> BYTE_ARRAY_CLASS;
@ -223,6 +230,9 @@ public class PKCS9Attribute implements DerEncoder {
public static final ObjectIdentifier SIGNATURE_TIMESTAMP_TOKEN_OID =
PKCS9_OIDS[17] =
ObjectIdentifier.of(KnownOIDs.SignatureTimestampToken);
public static final ObjectIdentifier CMS_ALGORITHM_PROTECTION_OID =
PKCS9_OIDS[18] =
ObjectIdentifier.of(KnownOIDs.CMSAlgorithmProtection);
/**
* Acceptable ASN.1 tags for DER encodings of values of PKCS9
@ -261,10 +271,11 @@ public class PKCS9Attribute implements DerEncoder {
{DerValue.tag_Sequence}, // extensionRequest
{DerValue.tag_Sequence}, // SMIMECapability
{DerValue.tag_Sequence}, // SigningCertificate
{DerValue.tag_Sequence} // SignatureTimestampToken
{DerValue.tag_Sequence}, // SignatureTimestampToken
{DerValue.tag_Sequence} // CMSAlgorithmProtection
};
private static final Class<?>[] VALUE_CLASSES = new Class<?>[18];
private static final Class<?>[] VALUE_CLASSES = new Class<?>[19];
static {
try {
@ -292,6 +303,7 @@ public class PKCS9Attribute implements DerEncoder {
VALUE_CLASSES[15] = null; // not supported yet
VALUE_CLASSES[16] = null; // not supported yet
VALUE_CLASSES[17] = BYTE_ARRAY_CLASS; // SignatureTimestampToken
VALUE_CLASSES[18] = BYTE_ARRAY_CLASS; // CMSAlgorithmProtection
} catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError(e.toString());
}
@ -319,7 +331,8 @@ public class PKCS9Attribute implements DerEncoder {
true, // ExtensionRequest
true, // SMIMECapability - not supported yet
true, // SigningCertificate
true // SignatureTimestampToken
true, // SignatureTimestampToken
true, // CMSAlgorithmProtection
};
/**
@ -496,6 +509,11 @@ public class PKCS9Attribute implements DerEncoder {
case 17: // SignatureTimestampToken attribute
value = elems[0].toByteArray();
break;
case 18: // CMSAlgorithmProtection
value = elems[0].toByteArray();
break;
default: // can't happen
}
}
@ -623,6 +641,10 @@ public class PKCS9Attribute implements DerEncoder {
temp.write(DerValue.tag_Set, (byte[])value);
break;
case 18: // CMSAlgorithmProtection
temp.write(DerValue.tag_Set, (byte[])value);
break;
default: // can't happen
}

View File

@ -34,27 +34,19 @@ import java.security.cert.CertificateFactory;
import java.security.cert.CertPath;
import java.security.cert.X509Certificate;
import java.security.*;
import java.security.spec.PSSParameterSpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
import sun.security.provider.SHAKE256;
import sun.security.timestamp.TimestampToken;
import sun.security.util.ConstraintsParameters;
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.HexDumpEncoder;
import sun.security.util.KeyUtil;
import sun.security.util.ObjectIdentifier;
import sun.security.util.*;
import sun.security.x509.AlgorithmId;
import sun.security.x509.X500Name;
import sun.security.x509.KeyUsageExtension;
import sun.security.util.SignatureUtil;
/**
* A SignerInfo, as defined in PKCS#7's signedData type.
@ -92,12 +84,8 @@ public class SignerInfo implements DerEncoder {
AlgorithmId digestAlgorithmId,
AlgorithmId digestEncryptionAlgorithmId,
byte[] encryptedDigest) {
this.version = BigInteger.ONE;
this.issuerName = issuerName;
this.certificateSerialNumber = serial;
this.digestAlgorithmId = digestAlgorithmId;
this.digestEncryptionAlgorithmId = digestEncryptionAlgorithmId;
this.encryptedDigest = encryptedDigest;
this(issuerName, serial, digestAlgorithmId, null,
digestEncryptionAlgorithmId, encryptedDigest, null);
}
public SignerInfo(X500Name issuerName,
@ -198,6 +186,36 @@ public class SignerInfo implements DerEncoder {
if (derin.available() != 0) {
throw new ParsingException("extra data at the end");
}
// verify CMSAlgorithmProtection
checkCMSAlgorithmProtection();
}
// CMSAlgorithmProtection verification as described in RFC 6211
private void checkCMSAlgorithmProtection() throws IOException {
if (authenticatedAttributes == null) {
return;
}
PKCS9Attribute ap = authenticatedAttributes.getAttribute(
PKCS9Attribute.CMS_ALGORITHM_PROTECTION_OID);
if (ap == null) {
return;
}
DerValue dv = new DerValue((byte[])ap.getValue());
DerInputStream data = dv.data();
AlgorithmId d = AlgorithmId.parse(data.getDerValue());
DerValue ds = data.getDerValue();
if (data.available() > 0) {
throw new IOException("Unknown field in CMSAlgorithmProtection");
}
if (!ds.isContextSpecific((byte)1)) {
throw new IOException("No signature algorithm in CMSAlgorithmProtection");
}
AlgorithmId s = AlgorithmId.parse(ds.withTag(DerValue.tag_Sequence));
if (!s.equals(digestEncryptionAlgorithmId)
|| !d.equals(digestAlgorithmId)) {
throw new IOException("CMSAlgorithmProtection check failed");
}
}
public void encode(DerOutputStream out) throws IOException {
@ -327,7 +345,6 @@ public class SignerInfo implements DerEncoder {
ConstraintsParameters cparams =
new ConstraintsParameters(timestamp);
String digestAlgname = getDigestAlgorithmId().getName();
byte[] dataSigned;
@ -353,6 +370,8 @@ public class SignerInfo implements DerEncoder {
if (messageDigest == null) // fail if there is no message digest
return null;
String digestAlgname = digestAlgorithmId.getName();
// check that digest algorithm is not restricted
try {
JAR_DISABLED_CHECK.permits(digestAlgname, cparams);
@ -360,8 +379,24 @@ public class SignerInfo implements DerEncoder {
throw new SignatureException(e.getMessage(), e);
}
MessageDigest md = MessageDigest.getInstance(digestAlgname);
byte[] computedMessageDigest = md.digest(data);
byte[] computedMessageDigest;
if (digestAlgname.equals("SHAKE256")
|| digestAlgname.equals("SHAKE256-LEN")) {
if (digestAlgname.equals("SHAKE256-LEN")) {
int v = new DerValue(digestAlgorithmId
.getEncodedParams()).getInteger();
if (v != 512) {
throw new SignatureException(
"Unsupported id-shake256-" + v);
}
}
var md = new SHAKE256(64);
md.update(data, 0, data.length);
computedMessageDigest = md.digest();
} else {
MessageDigest md = MessageDigest.getInstance(digestAlgname);
computedMessageDigest = md.digest(data);
}
if (messageDigest.length != computedMessageDigest.length)
return null;
@ -380,16 +415,11 @@ public class SignerInfo implements DerEncoder {
}
// 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);
// to form signing algorithm. See makeSigAlg for details.
String algname = makeSigAlg(
digestAlgorithmId,
digestEncryptionAlgorithmId,
authenticatedAttributes == null);
// check that jar signature algorithm is not restricted
try {
@ -435,11 +465,11 @@ public class SignerInfo implements DerEncoder {
+ "extension");
}
boolean digSigAllowed = keyUsage.get(
KeyUsageExtension.DIGITAL_SIGNATURE).booleanValue();
boolean digSigAllowed
= keyUsage.get(KeyUsageExtension.DIGITAL_SIGNATURE);
boolean nonRepuAllowed = keyUsage.get(
KeyUsageExtension.NON_REPUDIATION).booleanValue();
boolean nonRepuAllowed
= keyUsage.get(KeyUsageExtension.NON_REPUDIATION);
if (!digSigAllowed && !nonRepuAllowed) {
throw new SignatureException("Key usage restricted: "
@ -471,6 +501,60 @@ public class SignerInfo implements DerEncoder {
return null;
}
/**
* Derives the signature algorithm name from the digest algorithm
* name and the encryption algorithm name inside a PKCS7 SignerInfo.
*
* For old style PKCS7 files where we use RSA, DSA, EC as encAlgId
* a DIGESTwithENC algorithm is returned. For new style RSASSA-PSS
* and EdDSA encryption, this method ensures digAlgId is compatible
* with the algorithm.
*
* @param digAlgId the digest algorithm
* @param encAlgId the encryption or signature algorithm
* @param directSign whether the signature is calculated on the content
* directly. This makes difference for Ed448.
*/
public static String makeSigAlg(AlgorithmId digAlgId, AlgorithmId encAlgId,
boolean directSign) throws NoSuchAlgorithmException {
String encAlg = encAlgId.getName();
if (encAlg.contains("with")) {
return encAlg;
}
switch (encAlg) {
case "RSASSA-PSS":
PSSParameterSpec spec = (PSSParameterSpec)
SignatureUtil.getParamSpec(encAlg, encAlgId.getParameters());
if (!AlgorithmId.get(spec.getDigestAlgorithm()).equals(digAlgId)) {
throw new NoSuchAlgorithmException("Incompatible digest algorithm");
}
return encAlg;
case "Ed25519":
if (!digAlgId.equals(SignatureUtil.EdDSADigestAlgHolder.sha512)) {
throw new NoSuchAlgorithmException("Incompatible digest algorithm");
}
return encAlg;
case "Ed448":
if (directSign) {
if (!digAlgId.equals(SignatureUtil.EdDSADigestAlgHolder.shake256)) {
throw new NoSuchAlgorithmException("Incompatible digest algorithm");
}
} else {
if (!digAlgId.equals(SignatureUtil.EdDSADigestAlgHolder.shake256$512)) {
throw new NoSuchAlgorithmException("Incompatible digest algorithm");
}
}
return encAlg;
default:
String digAlg = digAlgId.getName();
if (digAlg.startsWith("SHA-")) {
digAlg = "SHA" + digAlg.substring(4);
}
if (encAlg.equals("EC")) encAlg = "ECDSA";
return digAlg + "with" + encAlg;
}
}
/* Verify the content of the pkcs7 block. */
SignerInfo verify(PKCS7 block)
throws NoSuchAlgorithmException, SignatureException {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2020, 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
@ -30,7 +30,6 @@ import java.io.PrintStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.cert.CertificateException;
import java.security.*;
import java.util.Base64;
@ -189,19 +188,27 @@ public class PKCS10 {
* retrieved in either string or binary format.
*
* @param subject identifies the signer (by X.500 name).
* @param signature private key and signing algorithm to use.
* @param key private key to use.
* @param algorithm signing algorithm to use.
* @exception IOException on errors.
* @exception CertificateException on certificate handling errors.
* @exception SignatureException on signature handling errors.
* @exception NoSuchAlgorithmException algorithm is not recognized
* @exception InvalidKeyException key has a problem
*/
public void encodeAndSign(X500Name subject, Signature signature)
throws CertificateException, IOException, SignatureException {
public void encodeAndSign(X500Name subject, PrivateKey key, String algorithm)
throws IOException, SignatureException,
NoSuchAlgorithmException, InvalidKeyException {
DerOutputStream out, scratch;
byte[] certificateRequestInfo;
byte[] sig;
if (encoded != null)
if (encoded != null) {
throw new SignatureException("request is already signed");
}
Signature signature = SignatureUtil.fromKey(
algorithm, key, (Provider)null);
this.subject = subject;
@ -230,15 +237,7 @@ public class PKCS10 {
/*
* Build guts of SIGNED macro
*/
AlgorithmId algId = null;
try {
AlgorithmParameters params = signature.getParameters();
algId = params == null
? AlgorithmId.get(signature.getAlgorithm())
: AlgorithmId.get(params);
} catch (NoSuchAlgorithmException nsae) {
throw new SignatureException(nsae);
}
AlgorithmId algId = SignatureUtil.fromSignature(signature, key);
algId.encode(scratch); // sig algorithm
scratch.putBitString(sig); // sig

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2020, 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
@ -30,12 +30,12 @@ import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateEncodingException;
import java.security.*;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.NamedParameterSpec;
import java.util.Date;
import sun.security.pkcs10.PKCS10;
import sun.security.util.SignatureUtil;
import sun.security.x509.*;
/**
@ -187,7 +187,7 @@ public final class CertAndKeyGen {
}
if (sigAlg == null) {
sigAlg = AlgorithmId.getDefaultSigAlgForKey(privateKey);
sigAlg = SignatureUtil.getDefaultSigAlgForKey(privateKey);
if (sigAlg == null) {
throw new IllegalArgumentException(
"Cannot derive signature algorithm from "
@ -282,8 +282,6 @@ public final class CertAndKeyGen {
new CertificateValidity(firstDate,lastDate);
X509CertInfo info = new X509CertInfo();
AlgorithmParameterSpec params = AlgorithmId
.getDefaultAlgorithmParameterSpec(sigAlg, privateKey);
// Add all mandatory attributes
info.set(X509CertInfo.VERSION,
new CertificateVersion(CertificateVersion.V3));
@ -292,9 +290,6 @@ public final class CertAndKeyGen {
}
info.set(X509CertInfo.SERIAL_NUMBER,
CertificateSerialNumber.newRandom64bit(prng));
AlgorithmId algID = AlgorithmId.getWithParameterSpec(sigAlg, params);
info.set(X509CertInfo.ALGORITHM_ID,
new CertificateAlgorithmId(algID));
info.set(X509CertInfo.SUBJECT, myname);
info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
info.set(X509CertInfo.VALIDITY, interval);
@ -302,19 +297,13 @@ public final class CertAndKeyGen {
if (ext != null) info.set(X509CertInfo.EXTENSIONS, ext);
cert = new X509CertImpl(info);
cert.sign(privateKey,
params,
sigAlg,
null);
cert.sign(privateKey, sigAlg);
return (X509Certificate)cert;
return cert;
} catch (IOException e) {
throw new CertificateEncodingException("getSelfCert: " +
e.getMessage());
} catch (InvalidAlgorithmParameterException e2) {
throw new SignatureException(
"Unsupported PSSParameterSpec: " + e2.getMessage());
}
}
@ -326,44 +315,6 @@ public final class CertAndKeyGen {
return getSelfCertificate(myname, new Date(), validity);
}
/**
* Returns a PKCS #10 certificate request. The caller uses either
* <code>PKCS10.print</code> or <code>PKCS10.toByteArray</code>
* operations on the result, to get the request in an appropriate
* transmission format.
*
* <P>PKCS #10 certificate requests are sent, along with some proof
* of identity, to Certificate Authorities (CAs) which then issue
* X.509 public key certificates.
*
* @param myname X.500 name of the subject
* @exception InvalidKeyException on key handling errors.
* @exception SignatureException on signature handling errors.
*/
// This method is not used inside JDK. Will not update it.
public PKCS10 getCertRequest (X500Name myname)
throws InvalidKeyException, SignatureException
{
PKCS10 req = new PKCS10 (publicKey);
try {
Signature signature = Signature.getInstance(sigAlg);
signature.initSign (privateKey);
req.encodeAndSign(myname, signature);
} catch (CertificateException e) {
throw new SignatureException (sigAlg + " CertificateException");
} catch (IOException e) {
throw new SignatureException (sigAlg + " IOException");
} catch (NoSuchAlgorithmException e) {
// "can't happen"
throw new SignatureException (sigAlg + " unavailable?");
}
return req;
}
private SecureRandom prng;
private String keyType;
private String sigAlg;

View File

@ -28,21 +28,7 @@ package sun.security.tools.keytool;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.AlgorithmParameters;
import java.security.CodeSigner;
import java.security.CryptoPrimitive;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.Key;
import java.security.PublicKey;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.Timestamp;
import java.security.UnrecoverableEntryException;
import java.security.UnrecoverableKeyException;
import java.security.Principal;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.CertStoreException;
@ -53,6 +39,7 @@ import java.security.cert.URICertStoreParameters;
import java.security.interfaces.ECKey;
import java.security.interfaces.EdECKey;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECParameterSpec;
import java.text.Collator;
@ -100,7 +87,6 @@ import sun.security.util.Pem;
import sun.security.x509.*;
import static java.security.KeyStore.*;
import java.security.Security;
import static sun.security.tools.keytool.Main.Command.*;
import static sun.security.tools.keytool.Main.Option.*;
import sun.security.util.DisabledAlgorithmConstraints;
@ -1449,21 +1435,12 @@ public final class Main {
if (sigAlgName == null) {
sigAlgName = getCompatibleSigAlgName(privateKey);
}
Signature signature = Signature.getInstance(sigAlgName);
AlgorithmParameterSpec params = AlgorithmId
.getDefaultAlgorithmParameterSpec(sigAlgName, privateKey);
SignatureUtil.initSignWithParam(signature, privateKey, params, null);
X509CertInfo info = new X509CertInfo();
AlgorithmId algID = AlgorithmId.getWithParameterSpec(sigAlgName, params);
info.set(X509CertInfo.VALIDITY, interval);
info.set(X509CertInfo.SERIAL_NUMBER,
CertificateSerialNumber.newRandom64bit(new SecureRandom()));
info.set(X509CertInfo.VERSION,
new CertificateVersion(CertificateVersion.V3));
info.set(X509CertInfo.ALGORITHM_ID,
new CertificateAlgorithmId(algID));
info.set(X509CertInfo.ISSUER, issuer);
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
@ -1507,7 +1484,7 @@ public final class Main {
signerCert.getPublicKey());
info.set(X509CertInfo.EXTENSIONS, ext);
X509CertImpl cert = new X509CertImpl(info);
cert.sign(privateKey, params, sigAlgName, null);
cert.sign(privateKey, sigAlgName);
dumpCert(cert, out);
for (Certificate ca: keyStore.getCertificateChain(alias)) {
if (ca instanceof X509Certificate) {
@ -1608,17 +1585,12 @@ public final class Main {
sigAlgName = getCompatibleSigAlgName(privKey);
}
Signature signature = Signature.getInstance(sigAlgName);
AlgorithmParameterSpec params = AlgorithmId
.getDefaultAlgorithmParameterSpec(sigAlgName, privKey);
SignatureUtil.initSignWithParam(signature, privKey, params, null);
X500Name subject = dname == null?
new X500Name(((X509Certificate)cert).getSubjectX500Principal().getEncoded()):
new X500Name(dname);
// Sign the request and base-64 encode it
request.encodeAndSign(subject, signature);
request.encodeAndSign(subject, privKey, sigAlgName);
request.print(out);
checkWeak(rb.getString("the.generated.certificate.request"), request);
@ -1847,7 +1819,7 @@ public final class Main {
*/
private static String getCompatibleSigAlgName(PrivateKey key)
throws Exception {
String result = AlgorithmId.getDefaultSigAlgForKey(key);
String result = SignatureUtil.getDefaultSigAlgForKey(key);
if (result != null) {
return result;
} else {
@ -2537,7 +2509,7 @@ public final class Main {
private static String verifyCRL(KeyStore ks, CRL crl)
throws Exception {
X509CRLImpl xcrl = (X509CRLImpl)crl;
X509CRL xcrl = (X509CRL)crl;
X500Principal issuer = xcrl.getIssuerX500Principal();
for (String s: Collections.list(ks.aliases())) {
Certificate cert = ks.getCertificate(s);
@ -2545,7 +2517,7 @@ public final class Main {
X509Certificate xcert = (X509Certificate)cert;
if (xcert.getSubjectX500Principal().equals(issuer)) {
try {
((X509CRLImpl)crl).verify(cert.getPublicKey());
((X509CRL)crl).verify(cert.getPublicKey());
return s;
} catch (Exception e) {
}
@ -2983,18 +2955,6 @@ public final class Main {
certInfo.set(X509CertInfo.ISSUER + "." +
X509CertInfo.DN_NAME, owner);
// The inner and outer signature algorithms have to match.
// The way we achieve that is really ugly, but there seems to be no
// other solution: We first sign the cert, then retrieve the
// outer sigalg and use it to set the inner sigalg
X509CertImpl newCert = new X509CertImpl(certInfo);
AlgorithmParameterSpec params = AlgorithmId
.getDefaultAlgorithmParameterSpec(sigAlgName, privKey);
newCert.sign(privKey, params, sigAlgName, null);
AlgorithmId sigAlgid = (AlgorithmId)newCert.get(X509CertImpl.SIG_ALG);
certInfo.set(CertificateAlgorithmId.NAME + "." +
CertificateAlgorithmId.ALGORITHM, sigAlgid);
certInfo.set(X509CertInfo.VERSION,
new CertificateVersion(CertificateVersion.V3));
@ -3006,8 +2966,8 @@ public final class Main {
null);
certInfo.set(X509CertInfo.EXTENSIONS, ext);
// Sign the new certificate
newCert = new X509CertImpl(certInfo);
newCert.sign(privKey, params, sigAlgName, null);
X509CertImpl newCert = new X509CertImpl(certInfo);
newCert.sign(privKey, sigAlgName);
// Store the new certificate as a single-element certificate chain
keyStore.setKeyEntry(alias, privKey,
@ -3334,8 +3294,11 @@ public final class Main {
if (key instanceof ECKey) {
ECParameterSpec paramSpec = ((ECKey) key).getParams();
if (paramSpec instanceof NamedCurve) {
result += " (" + paramSpec.toString().split(" ")[0] + ")";
NamedCurve nc = (NamedCurve)paramSpec;
result += " (" + nc.getNameAndAliases()[0] + ")";
}
} else if (key instanceof EdECKey) {
result = ((EdECKey) key).getParams().getName();
}
return result;
}

View File

@ -148,6 +148,8 @@ public enum KnownOIDs {
HmacSHA3_256("2.16.840.1.101.3.4.2.14", "HmacSHA3-256"),
HmacSHA3_384("2.16.840.1.101.3.4.2.15", "HmacSHA3-384"),
HmacSHA3_512("2.16.840.1.101.3.4.2.16", "HmacSHA3-512"),
SHAKE128_LEN("2.16.840.1.101.3.4.2.17", "SHAKE128-LEN"),
SHAKE256_LEN("2.16.840.1.101.3.4.2.18", "SHAKE256-LEN"),
// sigAlgs 2.16.840.1.101.3.4.3.*
SHA224withDSA("2.16.840.1.101.3.4.3.1"),
@ -181,7 +183,7 @@ public enum KnownOIDs {
OAEP("1.2.840.113549.1.1.7"),
MGF1("1.2.840.113549.1.1.8"),
PSpecified("1.2.840.113549.1.1.9"),
RSASSA_PSS("1.2.840.113549.1.1.10", "RSASSA-PSS"),
RSASSA_PSS("1.2.840.113549.1.1.10", "RSASSA-PSS", "PSS"),
SHA256withRSA("1.2.840.113549.1.1.11"),
SHA384withRSA("1.2.840.113549.1.1.12"),
SHA512withRSA("1.2.840.113549.1.1.13"),
@ -231,6 +233,7 @@ public enum KnownOIDs {
FriendlyName("1.2.840.113549.1.9.20"),
LocalKeyID("1.2.840.113549.1.9.21"),
CertTypeX509("1.2.840.113549.1.9.22.1"),
CMSAlgorithmProtection("1.2.840.113549.1.9.52"),
// PKCS12 1.2.840.113549.1.12.*
PBEWithSHA1AndRC4_128("1.2.840.113549.1.12.1.1"),

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, 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
@ -31,6 +31,7 @@ import java.security.CodeSigner;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SignatureException;
import java.security.Timestamp;
import java.security.cert.CertPath;
@ -173,6 +174,7 @@ public class SignatureFileVerifier {
* @param s file name
* @return true if the input file name is a supported
* Signature File or PKCS7 block file name
* @see #getBlockExtension(PrivateKey)
*/
public static boolean isBlockOrSF(String s) {
// Note: keep this in sync with j.u.z.ZipFile.Source#isSignatureRelated
@ -183,6 +185,26 @@ public class SignatureFileVerifier {
|| s.endsWith(".EC");
}
/**
* Returns the signed JAR block file extension for a key.
*
* @param key the key used to sign the JAR file
* @return the extension
* @see #isBlockOrSF(String)
*/
public static String getBlockExtension(PrivateKey key) {
String keyAlgorithm = key.getAlgorithm().toUpperCase(Locale.ENGLISH);
if (keyAlgorithm.equals("RSASSA-PSS")) {
return "RSA";
} else if (keyAlgorithm.equals("EDDSA")
|| keyAlgorithm.equals("ED25519")
|| keyAlgorithm.equals("ED448")) {
return "EC";
} else {
return keyAlgorithm;
}
}
/**
* Yet another utility method used by JarVerifier and JarSigner
* to determine what files are signature related, which includes

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, 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
@ -27,10 +27,15 @@ package sun.security.util;
import java.io.IOException;
import java.security.*;
import java.security.interfaces.EdECKey;
import java.security.interfaces.EdECPrivateKey;
import java.security.interfaces.RSAKey;
import java.security.spec.*;
import java.util.Locale;
import sun.security.rsa.RSAUtil;
import jdk.internal.access.SharedSecrets;
import sun.security.x509.AlgorithmId;
/**
* Utility class for Signature related operations. Currently used by various
@ -41,15 +46,23 @@ import jdk.internal.access.SharedSecrets;
*/
public class SignatureUtil {
private static String checkName(String algName) throws ProviderException {
/**
* Convert OID.1.2.3.4 or 1.2.3.4 to its matching stdName.
*
* @param algName input, could be in any form
* @return the matching stdName, or {@code algName} if it is not in the
* form of an OID, or the OID value if no match is found.
*/
private static String checkName(String algName) {
if (algName.indexOf(".") == -1) {
return algName;
}
// convert oid to String
try {
return Signature.getInstance(algName).getAlgorithm();
} catch (Exception e) {
throw new ProviderException("Error mapping algorithm name", e);
} else {
// convert oid to String
if (algName.startsWith("OID.")) {
algName = algName.substring(4);
}
KnownOIDs ko = KnownOIDs.findMatch(algName);
return ko != null ? ko.stdName() : algName;
}
}
@ -69,15 +82,21 @@ public class SignatureUtil {
}
}
// Utility method for converting the specified AlgorithmParameters object
// into an AlgorithmParameterSpec object.
/**
* Utility method for converting the specified AlgorithmParameters object
* into an AlgorithmParameterSpec object.
*
* @param sigName signature algorithm
* @param params (optional) parameters
* @return an AlgorithmParameterSpec, null if {@code params} is null
*/
public static AlgorithmParameterSpec getParamSpec(String sigName,
AlgorithmParameters params)
throws ProviderException {
sigName = checkName(sigName).toUpperCase(Locale.ENGLISH);
AlgorithmParameterSpec paramSpec = null;
if (params != null) {
sigName = checkName(sigName).toUpperCase(Locale.ENGLISH);
// AlgorithmParameters.getAlgorithm() may returns oid if it's
// created during DER decoding. Convert to use the standard name
// before passing it to RSAUtil
@ -107,15 +126,21 @@ public class SignatureUtil {
return paramSpec;
}
// Utility method for converting the specified parameter bytes into an
// AlgorithmParameterSpec object.
/**
* Utility method for converting the specified parameter bytes
* into an AlgorithmParameterSpec object.
*
* @param sigName signature algorithm
* @param paramBytes (optional) parameter bytes
* @return an AlgorithmParameterSpec, null if {@code paramBytes} is null
*/
public static AlgorithmParameterSpec getParamSpec(String sigName,
byte[] paramBytes)
throws ProviderException {
sigName = checkName(sigName).toUpperCase(Locale.ENGLISH);
AlgorithmParameterSpec paramSpec = null;
if (paramBytes != null) {
sigName = checkName(sigName).toUpperCase(Locale.ENGLISH);
if (sigName.indexOf("RSA") != -1) {
AlgorithmParameters params =
createAlgorithmParameters(sigName, paramBytes);
@ -168,4 +193,342 @@ public class SignatureUtil {
InvalidKeyException {
SharedSecrets.getJavaSecuritySignatureAccess().initSign(s, key, params, sr);
}
public static class EdDSADigestAlgHolder {
public final static AlgorithmId sha512;
public final static AlgorithmId shake256;
public final static AlgorithmId shake256$512;
static {
try {
sha512 = new AlgorithmId(ObjectIdentifier.of(KnownOIDs.SHA_512));
shake256 = new AlgorithmId(ObjectIdentifier.of(KnownOIDs.SHAKE256));
shake256$512 = new AlgorithmId(
ObjectIdentifier.of(KnownOIDs.SHAKE256_LEN),
new DerValue((byte) 2, new byte[]{2, 0})); // int 512
} catch (IOException e) {
throw new AssertionError("Should not happen", e);
}
}
}
/**
* Determines the digestEncryptionAlgorithmId in PKCS7 SignerInfo.
*
* @param signer Signature object that tells you RSASSA-PSS params
* @param sigalg Signature algorithm
* @param privateKey key tells you EdDSA params
* @param directsign Ed448 uses different digest algs depending on this
* @return the digest algId
* @throws NoSuchAlgorithmException
*/
public static AlgorithmId getDigestAlgInPkcs7SignerInfo(
Signature signer, String sigalg, PrivateKey privateKey, boolean directsign)
throws NoSuchAlgorithmException {
AlgorithmId digAlgID;
String kAlg = privateKey.getAlgorithm();
if (privateKey instanceof EdECPrivateKey
|| kAlg.equalsIgnoreCase("Ed25519")
|| kAlg.equalsIgnoreCase("Ed448")) {
if (privateKey instanceof EdECPrivateKey) {
// Note: SunEC's kAlg is EdDSA, find out the real one
kAlg = ((EdECPrivateKey) privateKey).getParams().getName();
}
// https://www.rfc-editor.org/rfc/rfc8419.html#section-3
switch (kAlg.toUpperCase(Locale.ENGLISH)) {
case "ED25519":
digAlgID = EdDSADigestAlgHolder.sha512;
break;
case "ED448":
if (directsign) {
digAlgID = EdDSADigestAlgHolder.shake256;
} else {
digAlgID = EdDSADigestAlgHolder.shake256$512;
}
break;
default:
throw new AssertionError("Unknown curve name: " + kAlg);
}
} else {
if (sigalg.equalsIgnoreCase("RSASSA-PSS")) {
try {
digAlgID = AlgorithmId.get(signer.getParameters()
.getParameterSpec(PSSParameterSpec.class)
.getDigestAlgorithm());
} catch (InvalidParameterSpecException e) {
throw new AssertionError("Should not happen", e);
}
} else {
digAlgID = AlgorithmId.get(extractDigestAlgFromDwithE(sigalg));
}
}
return digAlgID;
}
/**
* Extracts the digest algorithm name from a signature
* algorithm name in either the "DIGESTwithENCRYPTION" or the
* "DIGESTwithENCRYPTIONandWHATEVER" format.
*
* It's OK to return "SHA1" instead of "SHA-1".
*/
public static String extractDigestAlgFromDwithE(String signatureAlgorithm) {
signatureAlgorithm = signatureAlgorithm.toUpperCase(Locale.ENGLISH);
int with = signatureAlgorithm.indexOf("WITH");
if (with > 0) {
return signatureAlgorithm.substring(0, with);
} else {
throw new IllegalArgumentException(
"Unknown algorithm: " + signatureAlgorithm);
}
}
/**
* Returns default AlgorithmParameterSpec for a key used in a signature.
* This is only useful for RSASSA-PSS now, which is the only algorithm
* that must be initialized with a AlgorithmParameterSpec now.
*/
public static AlgorithmParameterSpec getDefaultParamSpec(
String sigAlg, Key k) {
sigAlg = checkName(sigAlg);
if (sigAlg.equalsIgnoreCase("RSASSA-PSS")) {
if (k instanceof RSAKey) {
AlgorithmParameterSpec spec = ((RSAKey) k).getParams();
if (spec instanceof PSSParameterSpec) {
return spec;
}
}
switch (ifcFfcStrength(KeyUtil.getKeySize(k))) {
case "SHA256":
return PSSParamsHolder.PSS_256_SPEC;
case "SHA384":
return PSSParamsHolder.PSS_384_SPEC;
case "SHA512":
return PSSParamsHolder.PSS_512_SPEC;
default:
throw new AssertionError("Should not happen");
}
} else {
return null;
}
}
/**
* Create a Signature that has been initialized with proper key and params.
*
* @param sigAlg signature algorithms
* @param key public or private key
* @param provider (optional) provider
*/
public static Signature fromKey(String sigAlg, Key key, String provider)
throws NoSuchAlgorithmException, NoSuchProviderException,
InvalidKeyException{
Signature sigEngine = (provider == null || provider.isEmpty())
? Signature.getInstance(sigAlg)
: Signature.getInstance(sigAlg, provider);
return autoInitInternal(sigAlg, key, sigEngine);
}
/**
* Create a Signature that has been initialized with proper key and params.
*
* @param sigAlg signature algorithms
* @param key public or private key
* @param provider (optional) provider
*/
public static Signature fromKey(String sigAlg, Key key, Provider provider)
throws NoSuchAlgorithmException, InvalidKeyException{
Signature sigEngine = (provider == null)
? Signature.getInstance(sigAlg)
: Signature.getInstance(sigAlg, provider);
return autoInitInternal(sigAlg, key, sigEngine);
}
private static Signature autoInitInternal(String alg, Key key, Signature s)
throws InvalidKeyException {
AlgorithmParameterSpec params = SignatureUtil
.getDefaultParamSpec(alg, key);
try {
if (key instanceof PrivateKey) {
SignatureUtil.initSignWithParam(s, (PrivateKey) key, params,
null);
} else {
SignatureUtil.initVerifyWithParam(s, (PublicKey) key, params);
}
} catch (InvalidAlgorithmParameterException e) {
throw new AssertionError("Should not happen", e);
}
return s;
}
/**
* Derives AlgorithmId from a signature object and a key.
* @param sigEngine the signature object
* @param key the private key
* @return the AlgorithmId, not null
* @throws SignatureException if cannot find one
*/
public static AlgorithmId fromSignature(Signature sigEngine, PrivateKey key)
throws SignatureException {
try {
if (key instanceof EdECKey) {
return AlgorithmId.get(((EdECKey) key).getParams().getName());
}
AlgorithmParameters params = null;
try {
params = sigEngine.getParameters();
} catch (UnsupportedOperationException e) {
// some provider does not support it
}
if (params != null) {
return AlgorithmId.get(sigEngine.getParameters());
} else {
String sigAlg = sigEngine.getAlgorithm();
if (sigAlg.equalsIgnoreCase("EdDSA")) {
// Hopefully key knows if it's Ed25519 or Ed448
sigAlg = key.getAlgorithm();
}
return AlgorithmId.get(sigAlg);
}
} catch (NoSuchAlgorithmException e) {
// This could happen if both sig alg and key alg is EdDSA,
// we don't know which provider does this.
throw new SignatureException("Cannot derive AlgorithmIdentifier", e);
}
}
/**
* Checks if a signature algorithm matches a key, i.e. if this
* signature can be initialized with this key. Currently used
* in {@link jdk.security.jarsigner.JarSigner} to fail early.
*
* Note: Unknown signature algorithms are allowed.
*
* @param key must not be null
* @param sAlg must not be null
* @throws IllegalArgumentException if they are known to not match
*/
public static void checkKeyAndSigAlgMatch(PrivateKey key, String sAlg) {
String kAlg = key.getAlgorithm().toUpperCase(Locale.ENGLISH);
sAlg = checkName(sAlg).toUpperCase(Locale.ENGLISH);
switch (sAlg) {
case "RSASSA-PSS" -> {
if (!kAlg.equals("RSASSA-PSS")
&& !kAlg.equals("RSA")) {
throw new IllegalArgumentException(
"key algorithm not compatible with signature algorithm");
}
}
case "EDDSA" -> {
// General EdDSA, any EDDSA name variance is OK
if (!kAlg.equals("EDDSA") && !kAlg.equals("ED448")
&& !kAlg.equals("ED25519")) {
throw new IllegalArgumentException(
"key algorithm not compatible with signature algorithm");
}
}
case "ED25519", "ED448" -> {
// fix-size EdDSA
if (key instanceof EdECKey) {
// SunEC's key alg is fix-size. Must match.
String groupName = ((EdECKey) key).getParams()
.getName().toUpperCase(Locale.US);
if (!sAlg.equals(groupName)) {
throw new IllegalArgumentException(
"key algorithm not compatible with signature algorithm");
}
} else {
// Other vendor might be generalized or fix-size
if (!kAlg.equals("EDDSA") && !kAlg.equals(sAlg)) {
throw new IllegalArgumentException(
"key algorithm not compatible with signature algorithm");
}
}
}
default -> {
if (sAlg.contains("WITH")) {
if ((sAlg.endsWith("WITHRSA") && !kAlg.equals("RSA")) ||
(sAlg.endsWith("WITHECDSA") && !kAlg.equals("EC")) ||
(sAlg.endsWith("WITHDSA") && !kAlg.equals("DSA"))) {
throw new IllegalArgumentException(
"key algorithm not compatible with signature algorithm");
}
}
// Do not fail now. Maybe new algorithm we don't know.
}
}
}
/**
* Returns the default signature algorithm for a private key.
*
* @param k cannot be null
* @return the default alg, might be null if unsupported
*/
public static String getDefaultSigAlgForKey(PrivateKey k) {
String kAlg = k.getAlgorithm();
return switch (kAlg.toUpperCase(Locale.ENGLISH)) {
case "DSA", "RSA" -> ifcFfcStrength(KeyUtil.getKeySize(k))
+ "with" + kAlg;
case "EC" -> ecStrength(KeyUtil.getKeySize(k))
+ "withECDSA";
case "EDDSA" -> k instanceof EdECPrivateKey
? ((EdECPrivateKey) k).getParams().getName()
: kAlg;
case "RSASSA-PSS", "ED25519", "ED448" -> kAlg;
default -> null;
};
}
// Useful PSSParameterSpec objects
private static class PSSParamsHolder {
final static PSSParameterSpec PSS_256_SPEC = new PSSParameterSpec(
"SHA-256", "MGF1",
new MGF1ParameterSpec("SHA-256"),
32, PSSParameterSpec.TRAILER_FIELD_BC);
final static PSSParameterSpec PSS_384_SPEC = new PSSParameterSpec(
"SHA-384", "MGF1",
new MGF1ParameterSpec("SHA-384"),
48, PSSParameterSpec.TRAILER_FIELD_BC);
final static PSSParameterSpec PSS_512_SPEC = new PSSParameterSpec(
"SHA-512", "MGF1",
new MGF1ParameterSpec("SHA-512"),
64, PSSParameterSpec.TRAILER_FIELD_BC);
}
// The following values are from SP800-57 part 1 rev 4 tables 2 and 3
/**
* Return the default message digest algorithm with the same security
* strength as the specified EC key size.
*
* Attention: sync with the @implNote inside
* {@link jdk.security.jarsigner.JarSigner.Builder#getDefaultSignatureAlgorithm}.
*/
private static String ecStrength (int bitLength) {
if (bitLength >= 512) { // 256 bits of strength
return "SHA512";
} else if (bitLength >= 384) { // 192 bits of strength
return "SHA384";
} else { // 128 bits of strength and less
return "SHA256";
}
}
/**
* Return the default message digest algorithm with the same security
* strength as the specified IFC/FFC key size.
*
* Attention: sync with the @implNote inside
* {@link jdk.security.jarsigner.JarSigner.Builder#getDefaultSignatureAlgorithm}.
*/
private static String ifcFfcStrength (int bitLength) {
if (bitLength > 7680) { // 256 bits
return "SHA512";
} else if (bitLength > 3072) { // 192 bits
return "SHA384";
} else { // 128 bits and less
return "SHA256";
}
}
}

View File

@ -26,18 +26,10 @@
package sun.security.x509;
import java.io.*;
import java.security.interfaces.RSAKey;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.EdDSAParameterSpec;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PSSParameterSpec;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.security.*;
import java.security.interfaces.*;
import sun.security.rsa.PSSParameters;
import sun.security.util.*;
@ -110,7 +102,7 @@ public class AlgorithmId implements Serializable, DerEncoder {
* Constructs an algorithm ID with algorithm parameters.
*
* @param oid the identifier for the algorithm.
* @param algparams the associated algorithm parameters.
* @param algparams the associated algorithm parameters, can be null.
*/
public AlgorithmId(ObjectIdentifier oid, AlgorithmParameters algparams) {
algid = oid;
@ -118,7 +110,13 @@ public class AlgorithmId implements Serializable, DerEncoder {
constructedFromDer = false;
}
private AlgorithmId(ObjectIdentifier oid, DerValue params)
/**
* Constructs an algorithm ID with algorithm parameters as a DerValue.
*
* @param oid the identifier for the algorithm.
* @param params the associated algorithm parameters, can be null.
*/
public AlgorithmId(ObjectIdentifier oid, DerValue params)
throws IOException {
this.algid = oid;
this.params = params;
@ -270,10 +268,10 @@ public class AlgorithmId implements Serializable, DerEncoder {
if (o == KnownOIDs.SpecifiedSHA2withECDSA) {
if (params != null) {
try {
AlgorithmId paramsId =
AlgorithmId digestParams =
AlgorithmId.parse(new DerValue(params.toByteArray()));
String paramsName = paramsId.getName();
return makeSigAlg(paramsName, "EC");
String digestAlg = digestParams.getName();
return digestAlg.replace("-", "") + "withECDSA";
} catch (IOException e) {
// ignore
}
@ -668,210 +666,4 @@ public class AlgorithmId implements Serializable, DerEncoder {
ObjectIdentifier.of(KnownOIDs.SHA384withECDSA);
public static final ObjectIdentifier SHA512withECDSA_oid =
ObjectIdentifier.of(KnownOIDs.SHA512withECDSA);
/**
* Creates a signature algorithm name from a digest algorithm
* name and a encryption algorithm name.
*/
public static String makeSigAlg(String digAlg, String encAlg) {
digAlg = digAlg.replace("-", "");
if (encAlg.equalsIgnoreCase("EC")) encAlg = "ECDSA";
return digAlg + "with" + encAlg;
}
/**
* Extracts the encryption algorithm name from a signature
* algorithm name.
*/
public static String getEncAlgFromSigAlg(String signatureAlgorithm) {
signatureAlgorithm = signatureAlgorithm.toUpperCase(Locale.ENGLISH);
int with = signatureAlgorithm.indexOf("WITH");
String keyAlgorithm = null;
if (with > 0) {
int and = signatureAlgorithm.indexOf("AND", with + 4);
if (and > 0) {
keyAlgorithm = signatureAlgorithm.substring(with + 4, and);
} else {
keyAlgorithm = signatureAlgorithm.substring(with + 4);
}
if (keyAlgorithm.equalsIgnoreCase("ECDSA")) {
keyAlgorithm = "EC";
}
}
return keyAlgorithm;
}
/**
* Extracts the digest algorithm name from a signature
* algorithm name.
*/
public static String getDigAlgFromSigAlg(String signatureAlgorithm) {
signatureAlgorithm = signatureAlgorithm.toUpperCase(Locale.ENGLISH);
int with = signatureAlgorithm.indexOf("WITH");
if (with > 0) {
return signatureAlgorithm.substring(0, with);
}
return null;
}
/**
* Checks if a signature algorithm matches a key algorithm, i.e. a
* signature can be initialized with a key.
*
* @param kAlg must not be null
* @param sAlg must not be null
* @throws IllegalArgumentException if they do not match
*/
public static void checkKeyAndSigAlgMatch(String kAlg, String sAlg) {
String sAlgUp = sAlg.toUpperCase(Locale.US);
if ((sAlgUp.endsWith("WITHRSA") && !kAlg.equalsIgnoreCase("RSA")) ||
(sAlgUp.endsWith("WITHECDSA") && !kAlg.equalsIgnoreCase("EC")) ||
(sAlgUp.endsWith("WITHDSA") && !kAlg.equalsIgnoreCase("DSA"))) {
throw new IllegalArgumentException(
"key algorithm not compatible with signature algorithm");
}
}
/**
* Returns the default signature algorithm for a private key. The digest
* part might evolve with time. Remember to update the spec of
* {@link jdk.security.jarsigner.JarSigner.Builder#getDefaultSignatureAlgorithm(PrivateKey)}
* if updated.
*
* @param k cannot be null
* @return the default alg, might be null if unsupported
*/
public static String getDefaultSigAlgForKey(PrivateKey k) {
switch (k.getAlgorithm().toUpperCase(Locale.ENGLISH)) {
case "EC":
return ecStrength(KeyUtil.getKeySize(k))
+ "withECDSA";
case "DSA":
return ifcFfcStrength(KeyUtil.getKeySize(k))
+ "withDSA";
case "RSA":
return ifcFfcStrength(KeyUtil.getKeySize(k))
+ "withRSA";
case "RSASSA-PSS":
return "RSASSA-PSS";
case "EDDSA":
return edAlgFromKey(k);
default:
return null;
}
}
// Most commonly used PSSParameterSpec and AlgorithmId
private static class PSSParamsHolder {
final static PSSParameterSpec PSS_256_SPEC = new PSSParameterSpec(
"SHA-256", "MGF1",
new MGF1ParameterSpec("SHA-256"),
32, PSSParameterSpec.TRAILER_FIELD_BC);
final static PSSParameterSpec PSS_384_SPEC = new PSSParameterSpec(
"SHA-384", "MGF1",
new MGF1ParameterSpec("SHA-384"),
48, PSSParameterSpec.TRAILER_FIELD_BC);
final static PSSParameterSpec PSS_512_SPEC = new PSSParameterSpec(
"SHA-512", "MGF1",
new MGF1ParameterSpec("SHA-512"),
64, PSSParameterSpec.TRAILER_FIELD_BC);
final static AlgorithmId PSS_256_ID;
final static AlgorithmId PSS_384_ID;
final static AlgorithmId PSS_512_ID;
static {
try {
PSS_256_ID = new AlgorithmId(RSASSA_PSS_oid,
new DerValue(PSSParameters.getEncoded(PSS_256_SPEC)));
PSS_384_ID = new AlgorithmId(RSASSA_PSS_oid,
new DerValue(PSSParameters.getEncoded(PSS_384_SPEC)));
PSS_512_ID = new AlgorithmId(RSASSA_PSS_oid,
new DerValue(PSSParameters.getEncoded(PSS_512_SPEC)));
} catch (IOException e) {
throw new AssertionError("Should not happen", e);
}
}
}
public static AlgorithmId getWithParameterSpec(String algName,
AlgorithmParameterSpec spec) throws NoSuchAlgorithmException {
if (spec == null) {
return AlgorithmId.get(algName);
} else if (spec == PSSParamsHolder.PSS_256_SPEC) {
return PSSParamsHolder.PSS_256_ID;
} else if (spec == PSSParamsHolder.PSS_384_SPEC) {
return PSSParamsHolder.PSS_384_ID;
} else if (spec == PSSParamsHolder.PSS_512_SPEC) {
return PSSParamsHolder.PSS_512_ID;
} else if (spec instanceof EdDSAParameterSpec) {
return AlgorithmId.get(algName);
} else {
try {
AlgorithmParameters result =
AlgorithmParameters.getInstance(algName);
result.init(spec);
return get(result);
} catch (InvalidParameterSpecException | NoSuchAlgorithmException e) {
throw new ProviderException(e);
}
}
}
public static AlgorithmParameterSpec getDefaultAlgorithmParameterSpec(
String sigAlg, PrivateKey k) {
if (sigAlg.equalsIgnoreCase("RSASSA-PSS")) {
if (k instanceof RSAKey) {
AlgorithmParameterSpec spec = ((RSAKey) k).getParams();
if (spec instanceof PSSParameterSpec) {
return spec;
}
}
switch (ifcFfcStrength(KeyUtil.getKeySize(k))) {
case "SHA256":
return PSSParamsHolder.PSS_256_SPEC;
case "SHA384":
return PSSParamsHolder.PSS_384_SPEC;
case "SHA512":
return PSSParamsHolder.PSS_512_SPEC;
default:
throw new AssertionError("Should not happen");
}
} else {
return null;
}
}
private static String edAlgFromKey(PrivateKey k) {
if (k instanceof EdECPrivateKey) {
EdECPrivateKey edKey = (EdECPrivateKey) k;
return edKey.getParams().getName();
}
return "EdDSA";
}
// Values from SP800-57 part 1 rev 4 tables 2 and 3
private static String ecStrength (int bitLength) {
if (bitLength >= 512) { // 256 bits of strength
return "SHA512";
} else if (bitLength >= 384) { // 192 bits of strength
return "SHA384";
} else { // 128 bits of strength and less
return "SHA256";
}
}
// Same values for RSA and DSA
private static String ifcFfcStrength (int bitLength) {
if (bitLength > 7680) { // 256 bits
return "SHA512";
} else if (bitLength > 3072) { // 192 bits
return "SHA384";
} else { // 128 bits and less
return "SHA256";
}
}
}

View File

@ -35,7 +35,6 @@ import java.security.cert.X509Certificate;
import java.security.cert.X509CRLEntry;
import java.security.cert.CRLException;
import java.security.*;
import java.security.spec.AlgorithmParameterSpec;
import java.util.*;
import javax.security.auth.x500.X500Principal;
@ -457,16 +456,15 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* @param key the private key used for signing.
* @param algorithm the name of the signature algorithm used.
*
* @exception NoSuchAlgorithmException on unsupported signature
* algorithms.
* @exception NoSuchAlgorithmException on unsupported signature algorithms.
* @exception InvalidKeyException on incorrect key.
* @exception NoSuchProviderException on incorrect provider.
* @exception SignatureException on signature errors.
* @exception CRLException if any mandatory data was omitted.
*/
public void sign(PrivateKey key, String algorithm)
throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
NoSuchProviderException, SignatureException {
throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
NoSuchProviderException, SignatureException {
sign(key, algorithm, null);
}
@ -475,41 +473,23 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
*
* @param key the private key used for signing.
* @param algorithm the name of the signature algorithm used.
* @param provider the name of the provider.
* @param provider (optional) the name of the provider.
*
* @exception NoSuchAlgorithmException on unsupported signature
* algorithms.
* @exception NoSuchAlgorithmException on unsupported signature algorithms.
* @exception InvalidKeyException on incorrect key.
* @exception NoSuchProviderException on incorrect provider.
* @exception SignatureException on signature errors.
* @exception CRLException if any mandatory data was omitted.
*/
public void sign(PrivateKey key, String algorithm, String provider)
throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
NoSuchProviderException, SignatureException {
throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
NoSuchProviderException, SignatureException {
try {
if (readOnly)
throw new CRLException("cannot over-write existing CRL");
Signature sigEngine = null;
if (provider == null || provider.isEmpty())
sigEngine = Signature.getInstance(algorithm);
else
sigEngine = Signature.getInstance(algorithm, provider);
AlgorithmParameterSpec params = AlgorithmId
.getDefaultAlgorithmParameterSpec(algorithm, key);
try {
SignatureUtil.initSignWithParam(sigEngine, key, params, null);
} catch (InvalidAlgorithmParameterException e) {
throw new SignatureException(e);
}
if (params != null) {
sigAlgId = AlgorithmId.get(sigEngine.getParameters());
} else {
// in case the name is reset
sigAlgId = AlgorithmId.get(sigEngine.getAlgorithm());
}
Signature sigEngine = SignatureUtil.fromKey(algorithm, key, provider);
sigAlgId = SignatureUtil.fromSignature(sigEngine, key);
infoSigAlgId = sigAlgId;
DerOutputStream out = new DerOutputStream();

View File

@ -34,7 +34,6 @@ import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.AlgorithmParameterSpec;
import java.security.cert.*;
import java.security.cert.Certificate;
import java.util.*;
@ -278,6 +277,9 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
* Construct an initialized X509 Certificate. The certificate is stored
* in raw form and has to be signed to be useful.
*
* The ALGORITHM_ID attribute will be rewritten when signed. The initial
* value is ignored.
*
* @param certInfo the X509CertificateInfo which the Certificate is to be
* created from.
*/
@ -510,15 +512,14 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
* @param algorithm the name of the signature algorithm used.
*
* @exception InvalidKeyException on incorrect key.
* @exception NoSuchAlgorithmException on unsupported signature
* algorithms.
* @exception NoSuchAlgorithmException on unsupported signature algorithms.
* @exception NoSuchProviderException if there's no default provider.
* @exception SignatureException on signature errors.
* @exception CertificateException on encoding errors.
*/
public void sign(PrivateKey key, String algorithm)
throws CertificateException, NoSuchAlgorithmException,
InvalidKeyException, NoSuchProviderException, SignatureException {
throws CertificateException, NoSuchAlgorithmException,
InvalidKeyException, NoSuchProviderException, SignatureException {
sign(key, algorithm, null);
}
@ -530,79 +531,32 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
*
* @param key the private key used for signing.
* @param algorithm the name of the signature algorithm used.
* @param provider the name of the provider.
* @param provider (optional) the name of the provider.
*
* @exception NoSuchAlgorithmException on unsupported signature
* algorithms.
* @exception NoSuchAlgorithmException on unsupported signature algorithms.
* @exception InvalidKeyException on incorrect key.
* @exception NoSuchProviderException on incorrect provider.
* @exception SignatureException on signature errors.
* @exception CertificateException on encoding errors.
*/
public void sign(PrivateKey key, String algorithm, String provider)
throws CertificateException, NoSuchAlgorithmException,
InvalidKeyException, NoSuchProviderException, SignatureException {
try {
sign(key, null, algorithm, provider);
} catch (InvalidAlgorithmParameterException e) {
// should not happen; re-throw just in case
throw new SignatureException(e);
}
}
/**
* Creates an X.509 certificate, and signs it using the given key
* (associating a signature algorithm and an X.500 name), signature
* parameters, and security provider. If the given provider name
* is null or empty, the implementation look up will be based on
* provider configurations.
* This operation is used to implement the certificate generation
* functionality of a certificate authority.
*
* @param key the private key used for signing
* @param signingParams the parameters used for signing
* @param algorithm the name of the signature algorithm used
* @param provider the name of the provider, may be null
*
* @exception NoSuchAlgorithmException on unsupported signature
* algorithms
* @exception InvalidKeyException on incorrect key
* @exception InvalidAlgorithmParameterException on invalid signature
* parameters
* @exception NoSuchProviderException on incorrect provider
* @exception SignatureException on signature errors
* @exception CertificateException on encoding errors
*/
public void sign(PrivateKey key, AlgorithmParameterSpec signingParams,
String algorithm, String provider)
throws CertificateException, NoSuchAlgorithmException,
InvalidKeyException, InvalidAlgorithmParameterException,
NoSuchProviderException, SignatureException {
InvalidKeyException, NoSuchProviderException, SignatureException {
try {
if (readOnly) {
throw new CertificateEncodingException(
"cannot over-write existing certificate");
}
Signature sigEngine = null;
if (provider == null || provider.isEmpty()) {
sigEngine = Signature.getInstance(algorithm);
} else {
sigEngine = Signature.getInstance(algorithm, provider);
}
Signature sigEngine = SignatureUtil.fromKey(
algorithm, key, provider);
algId = SignatureUtil.fromSignature(sigEngine, key);
SignatureUtil.initSignWithParam(sigEngine, key, signingParams,
null);
if (signingParams != null) {
algId = AlgorithmId.get(sigEngine.getParameters());
} else {
// in case the name is reset
algId = AlgorithmId.get(sigEngine.getAlgorithm());
}
DerOutputStream out = new DerOutputStream();
DerOutputStream tmp = new DerOutputStream();
// encode certificate info
info.set(X509CertInfo.ALGORITHM_ID,
new CertificateAlgorithmId(algId));
info.encode(tmp);
byte[] rawCert = tmp.toByteArray();
@ -621,7 +575,7 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
} catch (IOException e) {
throw new CertificateEncodingException(e.toString());
}
}
}
/**

View File

@ -29,11 +29,16 @@ import com.sun.jarsigner.ContentSigner;
import com.sun.jarsigner.ContentSignerParameters;
import jdk.internal.access.JavaUtilZipFileAccess;
import jdk.internal.access.SharedSecrets;
import sun.security.pkcs.PKCS7;
import sun.security.pkcs.PKCS9Attribute;
import sun.security.pkcs.PKCS9Attributes;
import sun.security.timestamp.HttpTimestamper;
import sun.security.tools.PathList;
import sun.security.tools.jarsigner.TimestampedSigner;
import sun.security.util.Event;
import sun.security.util.ManifestDigester;
import sun.security.util.SignatureFileVerifier;
import sun.security.util.SignatureUtil;
import sun.security.x509.AlgorithmId;
import java.io.*;
@ -47,8 +52,10 @@ import java.security.cert.CertPath;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidParameterSpecException;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@ -113,8 +120,9 @@ public final class JarSigner {
// Implementation-specific properties:
String tSAPolicyID;
String tSADigestAlg;
boolean signManifest = true;
boolean externalSF = true;
boolean sectionsonly = false;
boolean internalsf = false;
boolean directsign = false;
String altSignerPath;
String altSigner;
@ -236,8 +244,7 @@ public final class JarSigner {
throws NoSuchAlgorithmException {
// Check availability
Signature.getInstance(Objects.requireNonNull(algorithm));
AlgorithmId.checkKeyAndSigAlgMatch(
privateKey.getAlgorithm(), algorithm);
SignatureUtil.checkKeyAndSigAlgMatch(privateKey, algorithm);
this.sigalg = algorithm;
this.sigProvider = null;
return this;
@ -267,8 +274,7 @@ public final class JarSigner {
Signature.getInstance(
Objects.requireNonNull(algorithm),
Objects.requireNonNull(provider));
AlgorithmId.checkKeyAndSigAlgMatch(
privateKey.getAlgorithm(), algorithm);
SignatureUtil.checkKeyAndSigAlgMatch(privateKey, algorithm);
this.sigalg = algorithm;
this.sigProvider = provider;
return this;
@ -352,6 +358,10 @@ public final class JarSigner {
* <li>"sectionsonly": "true" if the .SF file only contains the hash
* value for each section of the manifest and not for the whole
* manifest, "false" otherwise. Default "false".
* <li>"directsign": "true" if the signature is calculated on the
* content directly, "false" if it's calculated on signed attributes
* which itself is calculated from the content and stored in the
* signer's SignerInfo. Default "false".
* </ul>
* All property names are case-insensitive.
*
@ -380,30 +390,13 @@ public final class JarSigner {
this.tSAPolicyID = value;
break;
case "internalsf":
switch (value) {
case "true":
externalSF = false;
break;
case "false":
externalSF = true;
break;
default:
throw new IllegalArgumentException(
"Invalid internalsf value");
}
this.internalsf = parseBoolean("interalsf", value);
break;
case "sectionsonly":
switch (value) {
case "true":
signManifest = false;
break;
case "false":
signManifest = true;
break;
default:
throw new IllegalArgumentException(
"Invalid signManifest value");
}
this.sectionsonly = parseBoolean("sectionsonly", value);
break;
case "directsign":
this.directsign = parseBoolean("directsign", value);
break;
case "altsignerpath":
altSignerPath = value;
@ -418,6 +411,18 @@ public final class JarSigner {
return this;
}
private static boolean parseBoolean(String name, String value) {
switch (value) {
case "true":
return true;
case "false":
return false;
default:
throw new IllegalArgumentException(
"Invalid " + name + " value");
}
}
/**
* Gets the default digest algorithm.
*
@ -453,7 +458,9 @@ public final class JarSigner {
* will throw an {@link IllegalArgumentException}.
*/
public static String getDefaultSignatureAlgorithm(PrivateKey key) {
return AlgorithmId.getDefaultSigAlgForKey(Objects.requireNonNull(key));
// Attention: sync the spec with SignatureUtil::ecStrength and
// SignatureUtil::ifcFfcStrength.
return SignatureUtil.getDefaultSigAlgForKey(Objects.requireNonNull(key));
}
/**
@ -501,9 +508,13 @@ public final class JarSigner {
// Implementation-specific properties:
private final String tSAPolicyID;
private final String tSADigestAlg;
private final boolean signManifest; // "sign" the whole manifest
private final boolean externalSF; // leave the .SF out of the PKCS7 block
private final boolean sectionsonly; // do not "sign" the whole manifest
private final boolean internalsf; // include the .SF inside the PKCS7 block
private final boolean directsign;
@Deprecated(since="16", forRemoval=true)
private final String altSignerPath;
@Deprecated(since="16", forRemoval=true)
private final String altSigner;
private boolean extraAttrsDetected;
@ -545,10 +556,14 @@ public final class JarSigner {
this.tSADigestAlg = Builder.getDefaultDigestAlgorithm();
}
this.tSAPolicyID = builder.tSAPolicyID;
this.signManifest = builder.signManifest;
this.externalSF = builder.externalSF;
this.sectionsonly = builder.sectionsonly;
this.internalsf = builder.internalsf;
this.altSigner = builder.altSigner;
this.altSignerPath = builder.altSignerPath;
this.directsign = this.altSigner != null
? true
: builder.directsign;
}
/**
@ -574,7 +589,8 @@ public final class JarSigner {
throw new JarSignerException("Error applying timestamp", e);
} catch (IOException ioe) {
throw new JarSignerException("I/O error", ioe);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
} catch (NoSuchAlgorithmException | InvalidKeyException
| InvalidParameterSpecException e) {
throw new JarSignerException("Error in signer materials", e);
} catch (SignatureException se) {
throw new JarSignerException("Error creating signature", se);
@ -645,11 +661,13 @@ public final class JarSigner {
case "tsapolicyid":
return tSAPolicyID;
case "internalsf":
return Boolean.toString(!externalSF);
return Boolean.toString(internalsf);
case "sectionsonly":
return Boolean.toString(!signManifest);
return Boolean.toString(sectionsonly);
case "altsignerpath":
return altSignerPath;
case "directsign":
return Boolean.toString(directsign);
case "altsigner":
return altSigner;
default:
@ -660,7 +678,7 @@ public final class JarSigner {
private void sign0(ZipFile zipFile, OutputStream os)
throws IOException, CertificateException, NoSuchAlgorithmException,
SignatureException, InvalidKeyException {
SignatureException, InvalidKeyException, InvalidParameterSpecException {
MessageDigest[] digests;
try {
digests = new MessageDigest[digestalg.length];
@ -829,39 +847,70 @@ public final class JarSigner {
// Calculate SignatureFile (".SF") and SignatureBlockFile
ManifestDigester manDig = new ManifestDigester(mfRawBytes);
SignatureFile sf = new SignatureFile(digests, manifest, manDig,
signerName, signManifest);
signerName, sectionsonly);
byte[] block;
Signature signer;
if (sigProvider == null ) {
signer = Signature.getInstance(sigalg);
} else {
signer = Signature.getInstance(sigalg, sigProvider);
}
signer.initSign(privateKey);
baos.reset();
sf.write(baos);
byte[] content = baos.toByteArray();
signer.update(content);
byte[] signature = signer.sign();
// Use new method if directSign is false or it's a modern
// algorithm not supported by existing ContentSigner.
// Make this always true after we remove ContentSigner.
boolean useNewMethod = !directsign
|| !sigalg.toUpperCase(Locale.ENGLISH).contains("WITH");
@SuppressWarnings("removal")
ContentSigner signingMechanism = null;
if (altSigner != null) {
signingMechanism = loadSigningMechanism(altSigner,
altSignerPath);
// For newer sigalg without "with", always use the new PKCS7
// generateToken method. Otherwise, use deprecated ContentSigner.
if (useNewMethod) {
if (altSigner != null) {
throw new IllegalArgumentException(directsign
? ("Customized ContentSigner is not supported for " + sigalg)
: "Customized ContentSigner does not support authenticated attributes");
}
Function<byte[], PKCS9Attributes> timestamper = null;
if (tsaUrl != null) {
timestamper = s -> {
try {
// Timestamp the signature
HttpTimestamper tsa = new HttpTimestamper(tsaUrl);
byte[] tsToken = PKCS7.generateTimestampToken(
tsa, tSAPolicyID, tSADigestAlg, s);
return new PKCS9Attributes(new PKCS9Attribute[]{
new PKCS9Attribute(
PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_OID,
tsToken)});
} catch (IOException | CertificateException e) {
throw new RuntimeException(e);
}
};
}
// We now create authAttrs in block data, so "direct == false".
block = PKCS7.generateNewSignedData(sigalg, sigProvider, privateKey, certChain,
content, internalsf, directsign, timestamper);
} else {
Signature signer = SignatureUtil.fromKey(sigalg, privateKey, sigProvider);
signer.update(content);
byte[] signature = signer.sign();
@SuppressWarnings("removal")
ContentSignerParameters params =
new JarSignerParameters(null, tsaUrl, tSAPolicyID,
tSADigestAlg, signature,
signer.getAlgorithm(), certChain, content, zipFile);
@SuppressWarnings("removal")
ContentSigner signingMechanism = (altSigner != null)
? loadSigningMechanism(altSigner, altSignerPath)
: new TimestampedSigner();
block = signingMechanism.generateSignedData(
params,
!internalsf,
params.getTimestampingAuthority() != null
|| params.getTimestampingAuthorityCertificate() != null);
}
@SuppressWarnings("removal")
ContentSignerParameters params =
new JarSignerParameters(null, tsaUrl, tSAPolicyID,
tSADigestAlg, signature,
signer.getAlgorithm(), certChain, content, zipFile);
block = sf.generateBlock(params, externalSF, signingMechanism);
String sfFilename = sf.getMetaName();
String bkFilename = sf.getBlockName(privateKey);
@ -1121,7 +1170,7 @@ public final class JarSigner {
Manifest mf,
ManifestDigester md,
String baseName,
boolean signManifest) {
boolean sectionsonly) {
this.baseName = baseName;
@ -1134,7 +1183,7 @@ public final class JarSigner {
mattr.putValue(Attributes.Name.SIGNATURE_VERSION.toString(), "1.0");
mattr.putValue("Created-By", version + " (" + javaVendor + ")");
if (signManifest) {
if (!sectionsonly) {
for (MessageDigest digest: digests) {
mattr.putValue(digest.getAlgorithm() + "-Digest-Manifest",
Base64.getEncoder().encodeToString(
@ -1188,30 +1237,13 @@ public final class JarSigner {
// get .DSA (or .DSA, .EC) file name
public String getBlockName(PrivateKey privateKey) {
String keyAlgorithm = privateKey.getAlgorithm();
return getBaseSignatureFilesName(baseName) + keyAlgorithm;
}
// Generates the PKCS#7 content of block file
@SuppressWarnings("removal")
public byte[] generateBlock(ContentSignerParameters params,
boolean externalSF,
ContentSigner signingMechanism)
throws NoSuchAlgorithmException,
IOException, CertificateException {
if (signingMechanism == null) {
signingMechanism = new TimestampedSigner();
}
return signingMechanism.generateSignedData(
params,
externalSF,
params.getTimestampingAuthority() != null
|| params.getTimestampingAuthorityCertificate() != null);
String type = SignatureFileVerifier.getBlockExtension(privateKey);
return getBaseSignatureFilesName(baseName) + type;
}
}
@SuppressWarnings("removal")
@Deprecated(since="16", forRemoval=true)
class JarSignerParameters implements ContentSignerParameters {
private String[] args;

View File

@ -163,6 +163,7 @@ public class Main {
boolean debug = false; // debug
boolean signManifest = true; // "sign" the whole manifest
boolean externalSF = true; // leave the .SF out of the PKCS7 block
boolean directSign = false; // sign SF directly or thru signedAttrs
boolean strict = false; // treat warnings as error
boolean revocationCheck = false; // Revocation check flag
@ -472,6 +473,8 @@ public class Main {
signManifest = false;
} else if (collator.compare(flags, "-internalsf") ==0) {
externalSF = false;
} else if (collator.compare(flags, "-directsign") ==0) {
directSign = true;
} else if (collator.compare(flags, "-verify") ==0) {
verify = true;
} else if (collator.compare(flags, "-verbose") ==0) {
@ -660,6 +663,9 @@ public class Main {
System.out.println(rb.getString
(".internalsf.include.the.SF.file.inside.the.signature.block"));
System.out.println();
System.out.println(rb.getString
(".directsign.sign.the.SF.file.directly.no.signerinfo.signedattributes"));
System.out.println();
System.out.println(rb.getString
(".sectionsonly.don.t.compute.hash.of.entire.manifest"));
System.out.println();
@ -955,9 +961,10 @@ public class Main {
SignerInfo si = p7.getSignerInfos()[0];
X509Certificate signer = si.getCertificate(p7);
String digestAlg = digestMap.get(s);
String sigAlg = AlgorithmId.makeSigAlg(
si.getDigestAlgorithmId().getName(),
si.getDigestEncryptionAlgorithmId().getName());
String sigAlg = SignerInfo.makeSigAlg(
si.getDigestAlgorithmId(),
si.getDigestEncryptionAlgorithmId(),
si.getAuthenticatedAttributes() == null);
PublicKey key = signer.getPublicKey();
PKCS7 tsToken = si.getTsToken();
if (tsToken != null) {
@ -968,9 +975,10 @@ public class Main {
TimestampToken tsTokenInfo = new TimestampToken(encTsTokenInfo);
PublicKey tsKey = tsSigner.getPublicKey();
String tsDigestAlg = tsTokenInfo.getHashAlgorithm().getName();
String tsSigAlg = AlgorithmId.makeSigAlg(
tsSi.getDigestAlgorithmId().getName(),
tsSi.getDigestEncryptionAlgorithmId().getName());
String tsSigAlg = SignerInfo.makeSigAlg(
tsSi.getDigestAlgorithmId(),
tsSi.getDigestEncryptionAlgorithmId(),
tsSi.getAuthenticatedAttributes() == null);
Calendar c = Calendar.getInstance(
TimeZone.getTimeZone("UTC"),
Locale.getDefault(Locale.Category.FORMAT));
@ -1598,7 +1606,7 @@ public class Main {
/**
* Maps certificates (as keys) to alias names associated in the keystore
* {@link #store} (as values).
* {@link #keystore} (as values).
*/
Hashtable<Certificate, String> storeHash = new Hashtable<>();
@ -1725,7 +1733,7 @@ public class Main {
tsaURI = new URI(tsaUrl);
} else if (tsaAlias != null) {
tsaCert = getTsaCert(tsaAlias);
tsaURI = TimestampedSigner.getTimestampingURI(tsaCert);
tsaURI = PKCS7.getTimestampingURI(tsaCert);
}
if (tsaURI != null) {
@ -1765,6 +1773,7 @@ public class Main {
builder.setProperty("sectionsOnly", Boolean.toString(!signManifest));
builder.setProperty("internalSF", Boolean.toString(!externalSF));
builder.setProperty("directsign", Boolean.toString(directSign));
FileOutputStream fos = null;
try {
@ -1830,7 +1839,8 @@ public class Main {
// validate it.
try (JarFile check = new JarFile(signedJarFile)) {
PKCS7 p7 = new PKCS7(check.getInputStream(check.getEntry(
"META-INF/" + sigfile + "." + privateKey.getAlgorithm())));
"META-INF/" + sigfile + "."
+ SignatureFileVerifier.getBlockExtension(privateKey))));
Timestamp ts = null;
try {
SignerInfo si = p7.getSignerInfos()[0];

View File

@ -101,6 +101,8 @@ public class Resources extends java.util.ListResourceBundle {
" (This option is deprecated and will be removed in a future release.)"},
{".internalsf.include.the.SF.file.inside.the.signature.block",
"[-internalsf] include the .SF file inside the signature block"},
{".directsign.sign.the.SF.file.directly.no.signerinfo.signedattributes",
"[-directsign] sign the .SF file directly (no SignerInfo signedAttributes)"},
{".sectionsonly.don.t.compute.hash.of.entire.manifest",
"[-sectionsonly] don't compute hash of entire manifest"},
{".protected.keystore.has.protected.authentication.path",

View File

@ -33,8 +33,6 @@ import java.security.cert.X509Certificate;
import com.sun.jarsigner.*;
import sun.security.pkcs.PKCS7;
import sun.security.util.*;
import sun.security.x509.*;
/**
* This class implements a content signing service.
@ -45,15 +43,10 @@ import sun.security.x509.*;
*
* @author Vincent Ryan
*/
@Deprecated(since="16", forRemoval=true)
@SuppressWarnings("removal")
public final class TimestampedSigner extends ContentSigner {
/*
* Object identifier for the timestamping access descriptors.
*/
private static final ObjectIdentifier AD_TIMESTAMPING_Id =
ObjectIdentifier.of(KnownOIDs.AD_TimeStamping);
/**
* Instantiates a content signer that supports timestamped signatures.
*/
@ -93,12 +86,6 @@ public final class TimestampedSigner extends ContentSigner {
throw new NullPointerException();
}
// Parse the signature algorithm to extract the digest
// algorithm. The expected format is:
// "<digest>with<encryption>"
// or "<digest>with<encryption>and<mgf>"
String signatureAlgorithm = params.getSignatureAlgorithm();
X509Certificate[] signerChain = params.getSignerCertificateChain();
byte[] signature = params.getSignature();
@ -110,7 +97,7 @@ public final class TimestampedSigner extends ContentSigner {
tsaURI = params.getTimestampingAuthority();
if (tsaURI == null) {
// Examine TSA cert
tsaURI = getTimestampingURI(
tsaURI = PKCS7.getTimestampingURI(
params.getTimestampingAuthorityCertificate());
if (tsaURI == null) {
throw new CertificateException(
@ -123,52 +110,4 @@ public final class TimestampedSigner extends ContentSigner {
params.getTSAPolicyID(),
params.getTSADigestAlg());
}
/**
* Examine the certificate for a Subject Information Access extension
* (<a href="http://tools.ietf.org/html/rfc5280">RFC 5280</a>).
* The extension's {@code accessMethod} field should contain the object
* identifier defined for timestamping: 1.3.6.1.5.5.7.48.3 and its
* {@code accessLocation} field should contain an HTTP or HTTPS URL.
*
* @param tsaCertificate An X.509 certificate for the TSA.
* @return An HTTP or HTTPS URI or null if none was found.
*/
public static URI getTimestampingURI(X509Certificate tsaCertificate) {
if (tsaCertificate == null) {
return null;
}
// Parse the extensions
try {
byte[] extensionValue = tsaCertificate.getExtensionValue
(KnownOIDs.SubjectInfoAccess.value());
if (extensionValue == null) {
return null;
}
DerInputStream der = new DerInputStream(extensionValue);
der = new DerInputStream(der.getOctetString());
DerValue[] derValue = der.getSequence(5);
AccessDescription description;
GeneralName location;
URIName uri;
for (int i = 0; i < derValue.length; i++) {
description = new AccessDescription(derValue[i]);
if (description.getAccessMethod()
.equals(AD_TIMESTAMPING_Id)) {
location = description.getAccessLocation();
if (location.getType() == GeneralNameInterface.NAME_URI) {
uri = (URIName) location.getName();
if (uri.getScheme().equalsIgnoreCase("http") ||
uri.getScheme().equalsIgnoreCase("https")) {
return uri.getURI();
}
}
}
}
} catch (IOException ioe) {
// ignore
}
return null;
}
}

View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2020, 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8242068
* @summary test the properties
* @library /test/lib
* @modules java.base/sun.security.tools.keytool
* java.base/sun.security.x509
* java.base/sun.security.util
* jdk.jartool
*/
import jdk.security.jarsigner.JarSigner;
import jdk.test.lib.Asserts;
import jdk.test.lib.security.DerUtils;
import jdk.test.lib.util.JarUtils;
import sun.security.tools.keytool.CertAndKeyGen;
import sun.security.x509.X500Name;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.cert.CertificateFactory;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.zip.ZipFile;
public class Properties {
public static void main(String[] args) throws Exception {
Files.writeString(Path.of("anything"), "anything");
JarUtils.createJarFile(Path.of("src.jar"), Path.of("."),
Files.write(Path.of("anything"), new byte[100]));
var cakg = new CertAndKeyGen("EC", "SHA1withECDSA");
cakg.generate("secp256r1");
JarSigner.Builder jsb = new JarSigner.Builder(
cakg.getPrivateKey(),
CertificateFactory.getInstance("X.509").generateCertPath(List.of(
cakg.getSelfCertificate(new X500Name("CN=Me"), 100))));
jsb.signerName("E");
String sf;
byte[] i0 = sign(jsb.setProperty("internalsf", "false"));
// EncapsulatedContentInfo no content
DerUtils.shouldNotExist(i0, "1021");
byte[] i1 = sign(jsb.setProperty("internalsf", "true"));
// EncapsulatedContentInfo has content being the SF
sf = new String(DerUtils.innerDerValue(i1, "10210").getOctetString());
Asserts.assertTrue(sf.startsWith("Signature-Version"));
// There is a SignedAttributes
byte[] d0 = sign(jsb.setProperty("directsign", "false"));
Asserts.assertTrue(DerUtils.innerDerValue(d0, "10403")
.isContextSpecific((byte)0));
// There is no SignedAttributes
byte[] d1 = sign(jsb.setProperty("directsign", "true"));
Asserts.assertFalse(DerUtils.innerDerValue(d1, "10403")
.isContextSpecific((byte)0));
// Has a hash for the whole manifest
byte[] s0 = sign(jsb.setProperty("sectionsonly", "false"));
sf = new String(DerUtils.innerDerValue(s0, "10210").getOctetString());
Asserts.assertTrue(sf.contains("SHA-256-Digest-Manifest:"));
// Has no hash for the whole manifest
byte[] s1 = sign(jsb.setProperty("sectionsonly", "true"));
sf = new String(DerUtils.innerDerValue(s1, "10210").getOctetString());
Asserts.assertFalse(sf.contains("SHA-256-Digest-Manifest:"));
}
// Sign and returns the content of the PKCS7 signature block inside
static byte[] sign(JarSigner.Builder b) throws Exception {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try (ZipFile zf = new ZipFile("src.jar")) {
b.build().sign(zf, bout);
}
var jf = new JarInputStream(
new ByteArrayInputStream(bout.toByteArray()));
while (true) {
JarEntry je = jf.getNextJarEntry();
if (je == null) {
throw new RuntimeException("Cannot find signature");
}
if (je.getName().equals("META-INF/E.EC")) {
return jf.readAllBytes();
}
}
}
}

View File

@ -23,7 +23,7 @@
/**
* @test
* @bug 8056174
* @bug 8056174 8242068
* @summary Make sure JarSigner impl conforms to spec
* @library /test/lib
* @modules java.base/sun.security.tools.keytool
@ -125,7 +125,10 @@ public class Spec {
iae(()->b1.setProperty("internalsf", "Hello"));
npe(()->b1.setProperty("sectionsonly", null));
iae(()->b1.setProperty("sectionsonly", "OK"));
npe(()->b1.setProperty("sectionsonly", null));
npe(()->b1.setProperty("altsigner", null));
iae(()->b1.setProperty("directsign", "OK"));
npe(()->b1.setProperty("directsign", null));
npe(()->b1.eventHandler(null));
// default values
@ -143,6 +146,7 @@ public class Spec {
assertTrue(js2.getProperty("tsapolicyid") == null);
assertTrue(js2.getProperty("internalsf").equals("false"));
assertTrue(js2.getProperty("sectionsonly").equals("false"));
assertTrue(js2.getProperty("directsign").equals("false"));
assertTrue(js2.getProperty("altsigner") == null);
uoe(()->js2.getProperty("invalid"));
@ -159,6 +163,7 @@ public class Spec {
.setProperty("tsapolicyid", "1.2.3.4")
.setProperty("internalsf", "true")
.setProperty("sectionsonly", "true")
.setProperty("directsign", "true")
.setProperty("altsigner", "MyContentSigner")
.eventHandler(myeh);
JarSigner js3 = b3.build();
@ -171,6 +176,7 @@ public class Spec {
assertTrue(js3.getProperty("tsapolicyid").equals("1.2.3.4"));
assertTrue(js3.getProperty("internalsf").equals("true"));
assertTrue(js3.getProperty("sectionsonly").equals("true"));
assertTrue(js3.getProperty("directsign").equals("true"));
assertTrue(js3.getProperty("altsigner").equals("MyContentSigner"));
assertTrue(js3.getProperty("altsignerpath") == null);

View File

@ -35,7 +35,6 @@
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.Enumeration;
import java.util.GregorianCalendar;
import java.util.HashMap;
@ -80,9 +79,6 @@ public class PKCS10AttrEncoding {
X509Key publicKey = (X509Key) pair.getPublic();
PrivateKey privateKey = pair.getPrivate();
Signature signature = Signature.getInstance(sigAlg);
signature.initSign(privateKey);
// Create the PKCS10 request
PKCS10Attribute[] attrs = new PKCS10Attribute[len];
for (int j = 0; j < len; j++) {
@ -95,7 +91,7 @@ public class PKCS10AttrEncoding {
// Encode the PKCS10 request and generate another PKCS10 request from
// the encoded byte array
req.encodeAndSign(subject, signature);
req.encodeAndSign(subject, privateKey, sigAlg);
PKCS10 resp = new PKCS10(req.getEncoded());
System.out.println("List of attributes in DER encoded PKCS10 Request:");
checkAttributes(resp.getAttributes().getElements());

View File

@ -22,14 +22,11 @@
*/
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
@ -57,7 +54,7 @@ import sun.security.timestamp.TimestampToken;
/*
* @test
* @bug 6543842 6543440 6939248 8009636 8024302 8163304 8169911 8180289 8172404 8247960
* @bug 6543842 6543440 6939248 8009636 8024302 8163304 8169911 8180289 8172404 8247960 8242068
* @summary checking response of timestamp
* @modules java.base/sun.security.pkcs
* java.base/sun.security.timestamp
@ -355,6 +352,26 @@ public class TimestampCheck {
.shouldHaveExitValue(4);
checkMultiple("sign2.jar");
// signed with everyone
signVerbose("normal", "unsigned.jar", "signall.jar", "signer",
"-sigalg", "SHA3-256withRSA")
.shouldHaveExitValue(0);
signVerbose("normal", "signall.jar", "signall.jar", "dsakey")
.shouldHaveExitValue(0);
signVerbose("normal", "signall.jar", "signall.jar", "eckey")
.shouldHaveExitValue(0);
signVerbose("normal", "signall.jar", "signall.jar", "psskey")
.shouldHaveExitValue(0);
signVerbose("normal", "signall.jar", "signall.jar", "edkey")
.shouldHaveExitValue(0);
verify("signall.jar", "-verbose")
.shouldHaveExitValue(0)
.shouldContain("Signature algorithm: SHA3-256withRSA")
.shouldContain("Signature algorithm: RSASSA-PSS")
.shouldContain("Signature algorithm: SHA256withECDSA")
.shouldContain("Signature algorithm: Ed25519")
.shouldContain("Signature algorithm: SHA256withDSA");
// Legacy algorithms
sign("tsweak", "-digestalg", "SHA1",
"-sigalg", "SHA1withRSA", "-tsadigestalg", "SHA1")
@ -817,6 +834,9 @@ public class TimestampCheck {
keytool("-alias signer -genkeypair -ext bc -dname CN=signer");
keytool("-alias oldsigner -genkeypair -dname CN=oldsigner");
keytool("-alias dsakey -genkeypair -keyalg DSA -dname CN=dsakey");
keytool("-alias eckey -genkeypair -keyalg EC -dname CN=eckey");
keytool("-alias psskey -genkeypair -keyalg RSASSA-PSS -dname CN=psskey");
keytool("-alias edkey -genkeypair -keyalg Ed25519 -dname CN=edkey");
keytool("-alias weakkeysize -genkeypair -keysize 1024 -dname CN=weakkeysize");
keytool("-alias disabledkeysize -genkeypair -keysize 512 -dname CN=disabledkeysize");
keytool("-alias badku -genkeypair -dname CN=badku");
@ -846,6 +866,9 @@ public class TimestampCheck {
gencert("signer");
gencert("oldsigner", "-startdate -30d -validity 20");
gencert("dsakey");
gencert("eckey");
gencert("psskey");
gencert("edkey");
gencert("weakkeysize");
gencert("disabledkeysize");
gencert("badku", "-ext ku:critical=keyAgreement");

View File

@ -23,51 +23,224 @@
/*
* @test
* @bug 8242184
* @summary CRL generation error with RSASSA-PSS
* @bug 8242184 8242068
* @summary keytool and jarsigner for all algorithms
* @library /test/lib
* @modules java.base/sun.security.util
* @run testng/timeout=300 GenerateAll
*/
import jdk.test.lib.SecurityTools;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.security.DerUtils;
import jdk.test.lib.util.JarUtils;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
import static sun.security.util.KnownOIDs.*;
import sun.security.util.KnownOIDs;
import sun.security.util.ObjectIdentifier;
import sun.security.util.SignatureUtil;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.util.Base64;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
public class GenerateAll {
public static void main(String[] args) throws Throwable {
@BeforeTest
public void beforeTest() throws Exception {
// Create a CA in a separate keystore
kt("-genkeypair -alias ca -dname CN=CA -keyalg ec -ext bc -keystore ca");
kt("-export -alias ca -file ca.crt -rfc -keystore ca");
kt("-genkeypair -alias ca -dname CN=CA -keyalg ec");
// Import CA cert to user keystore so we can import reply later
kt("-import -alias root -file ca.crt -noprompt");
String[] aliases = {
"rsa", "dsa", "rrr", "rsassa-pss", "ec"};
JarUtils.createJarFile(Path.of("a.jar"), Path.of("."), Path.of("ks"));
}
for (String alias : aliases) {
// "rrr": keyalg is rsa, sigalg is rsassa-pss
// otherwise: keyalg is alias, sigalg auto derived
String keyAlg = alias.equals("rrr") ? "rsa" : alias;
String extra = alias.equals("rrr") ? " -sigalg rsassa-pss" : "";
@DataProvider(name = "eddsa")
public Object[][] eddsaData() {
return new Object[][]{
{"eddsa", null, "ed25519"},
{"eddsa", "eddsa", "ed25519"},
{"eddsa", "ed25519", "ed25519"},
{"eddsa", "ed448", null},
{"ed25519", null, "ed25519"},
{"ed25519", "eddsa", "ed25519"},
{"ed25519", "ed25519", "ed25519"},
{"ed25519", "ed448", null},
{"ed448", null, "ed448"},
{"ed448", "eddsa", "ed448"},
{"ed448", "ed25519", null},
{"ed448", "ed448", "ed448"},
};
}
// gen
kt("-genkeypair -alias " + alias + " -dname CN=" + alias
+ " -keyalg " + keyAlg + extra);
/**
* Test various names of EdDSA
* @param keyAlg keytool -keyalg
* @param sigAlg (optional) keytool -sigalg
* @param expected expected algorithm of generated signature
*/
@Test(dataProvider = "eddsa")
public void eddsaTest(String keyAlg, String sigAlg, String expected)
throws Exception {
String alias = keyAlg + "-" + sigAlg;
OutputAnalyzer oa = kt0("-genkeypair -alias " + alias
+ " -dname CN=" + alias + " -keyalg " + keyAlg
+ (sigAlg == null ? "" : (" -sigalg " + sigAlg)));
if (expected == null) {
oa.shouldNotHaveExitValue(0);
} else {
oa.shouldHaveExitValue(0);
kt("-alias " + alias + " -export -file " + alias + ".crt");
byte[] crt = Files.readAllBytes(Path.of(alias + ".crt"));
ObjectIdentifier oid = oid(expected);
DerUtils.checkAlg(crt, "020", oid); // tbsCertificate.signature
DerUtils.checkAlg(crt, "0600", oid); // tbsCertificate.subjectPublicKeyInfo.algorithm
DerUtils.checkAlg(crt, "10", oid); // signatureAlgorithm
}
}
// req
kt("-certreq -alias " + alias + " -file " + alias + ".req");
kt("-printcertreq -file " + alias + ".req");
@DataProvider(name = "all")
public Object[][] dataProvider() {
return new Object[][]{
{"rsa", "rsa", null, "RSA", SHA_256, SHA256withRSA},
{"dsa", "dsa", null, "DSA", SHA_256, SHA256withDSA},
{"r", "rsa", "rsassa-pss", "RSA", SHA_256, RSASSA_PSS},
{"pss", "rsassa-pss", null, "RSA", SHA_256, RSASSA_PSS},
{"ec", "ec", null, "EC", SHA_256, SHA256withECDSA},
{"ed25519", "ed25519", null, "EC", SHA_512, Ed25519},
{"ed448", "ed448", null, "EC", SHAKE256_LEN, Ed448},
};
}
// gencert
kt("-gencert -alias ca -infile " + alias
+ ".req -outfile " + alias + ".crt");
kt("-printcert -file " + alias + ".crt");
/**
* Testing all algorithms.
* @param alias alias
* @param keyAlg keytool -keyalg
* @param sigAlg (optional) keytool -sigalg
* @param ext block extension inside signed JAR
* @param expDigAlg expected digAlg in PKCS7 SignerInfo
* @param expEncAlg expected encAlg in PKCS7 SignerInfo
*/
@Test(dataProvider = "all")
public void test(String alias, String keyAlg, String sigAlg, String ext,
KnownOIDs expDigAlg, KnownOIDs expEncAlg) throws Throwable {
// crl
kt("-gencrl -alias " + alias + " -id 0 -file " + alias + ".crl");
kt("-printcrl -file " + alias + ".crl")
.shouldContain("Verified by " + alias);
char[] pass = "changeit".toCharArray();
// If no sigAlg, derive automatically
String extra = sigAlg == null ? "" : (" -sigalg " + sigAlg);
// gen
kt("-genkeypair -alias " + alias + " -dname CN=" + alias
+ " -keyalg " + keyAlg + extra);
kt("-export -alias " + alias + " -rfc -file " + alias + ".self");
// req
kt("-certreq -alias " + alias + " -file " + alias + ".req" + extra);
kt("-printcertreq -file " + alias + ".req");
// gencert
kt("-gencert -alias ca -infile " + alias
+ ".req -outfile " + alias + ".crt -rfc -keystore ca");
kt("-printcert -file " + alias + ".crt");
kt("-importcert -alias " + alias + " -file " + alias + ".crt");
// crl
kt("-gencrl -alias " + alias + " -id 0 -rfc -file "
+ alias + ".crl" + extra);
kt("-printcrl -file " + alias + ".crl")
.shouldContain("Verified by " + alias);
// sign
js("a.jar " + alias + extra);
// check data
KeyStore ks = KeyStore.getInstance(new File("ks"), pass);
PrivateKey pk = (PrivateKey)ks.getKey(alias, pass);
if (sigAlg == null) {
sigAlg = SignatureUtil.getDefaultSigAlgForKey(pk);
}
byte[] crt = read(alias + ".self");
DerUtils.checkAlg(crt, "020", oid(sigAlg)); // tbsCertificate.signature
DerUtils.checkAlg(crt, "0600", oid(keyAlg)); // tbsCertificate.subjectPublicKeyInfo.algorithm
assertEquals(
DerUtils.innerDerValue(crt, "02"), // tbsCertificate.signature
DerUtils.innerDerValue(crt, "1")); // signatureAlgorithm
byte[] req = read(alias + ".req");
DerUtils.checkAlg(req, "10", oid(sigAlg)); // signatureAlgorithm
DerUtils.checkAlg(req, "0200", oid(keyAlg)); // certificationRequestInfo.subjectPKInfo.algorithm
byte[] crl = read(alias + ".crl");
DerUtils.checkAlg(crl, "000", oid(sigAlg)); // tbsCertList.signature
assertEquals(
DerUtils.innerDerValue(crl, "00"), // tbsCertList.signature
DerUtils.innerDerValue(crl, "1")); // signatureAlgorithm
try (JarFile jf = new JarFile("a.jar")) {
JarEntry je = jf.getJarEntry(
"META-INF/" + alias.toUpperCase() + "." + ext);
byte[] p7 = jf.getInputStream(je).readAllBytes();
// SignerInfo.digestAlgorithm
DerUtils.checkAlg(p7, "104020", oid(expDigAlg));
// SignerInfo.signatureAlgorithm
if (DerUtils.innerDerValue(p7, "10403").isContextSpecific()) {
// SignerInfo has signedAttributes at 104030
DerUtils.checkAlg(p7, "104040", oid(expEncAlg));
} else {
DerUtils.checkAlg(p7, "104030", oid(expEncAlg));
}
}
}
@AfterTest
public void afterTest() throws Exception {
js("-verify a.jar -verbose -certs");
}
static ObjectIdentifier oid(String name) {
return ObjectIdentifier.of(KnownOIDs.findMatch(name));
}
static ObjectIdentifier oid(KnownOIDs ko) {
return ObjectIdentifier.of(ko);
}
static byte[] read(String f) throws IOException {
try (var v = Files.lines(Path.of(f))) {
return Base64.getDecoder().decode(v.filter(s -> !s.startsWith("-----"))
.collect(Collectors.joining("")));
}
}
static OutputAnalyzer kt(String arg) throws Exception {
return SecurityTools.keytool("-keystore ks -storepass changeit " + arg)
return kt0(arg).shouldHaveExitValue(0);
}
static OutputAnalyzer kt0(String arg) throws Exception {
return SecurityTools.keytool("-keystore ks -storepass changeit " + arg);
}
static OutputAnalyzer js(String arg) throws Exception {
return SecurityTools.jarsigner("-keystore ks -storepass changeit " + arg)
.shouldHaveExitValue(0);
}
}

View File

@ -33,15 +33,13 @@ import java.security.cert.X509Certificate;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.*;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import sun.security.util.KnownOIDs;
import sun.security.util.SignatureUtil;
import sun.security.x509.AlgorithmId;
/**
@ -208,9 +206,18 @@ public class TsaHandler implements HttpHandler {
protected String getSignerAlias(String alias, String sigAlgo)
throws Exception {
if (alias == null) {
String keyAlgo = sigAlgo == null
? null
: AlgorithmId.getEncAlgFromSigAlg(sigAlgo);
String keyAlgo;
if (sigAlgo == null) {
keyAlgo = null;
} else {
String lower = sigAlgo.toLowerCase(Locale.ROOT);
int pos = lower.indexOf("with");
if (pos < 0) {
keyAlgo = sigAlgo;
} else {
keyAlgo = sigAlgo.substring(pos + 4);
}
}
Enumeration<String> aliases = keyStore.aliases();
while(aliases.hasMoreElements()) {
String bufAlias = aliases.nextElement();

View File

@ -34,10 +34,7 @@ import jdk.test.lib.hexdump.HexPrinter;
import sun.security.pkcs.ContentInfo;
import sun.security.pkcs.PKCS7;
import sun.security.pkcs.SignerInfo;
import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
import sun.security.util.KnownOIDs;
import sun.security.util.ObjectIdentifier;
import sun.security.util.*;
import sun.security.x509.AlgorithmId;
import sun.security.x509.X500Name;
@ -209,7 +206,7 @@ public class TsaSigner {
ObjectIdentifier.of(KnownOIDs.TimeStampTokenInfo),
new DerValue(eContentOut.toByteArray()));
String defaultSigAlgo = AlgorithmId.getDefaultSigAlgForKey(
String defaultSigAlgo = SignatureUtil.getDefaultSigAlgForKey(
signerEntry.privateKey);
String sigAlgo = interceptor.getSigAlgo(defaultSigAlgo);
Signature signature = Signature.getInstance(sigAlgo);
@ -221,8 +218,8 @@ public class TsaSigner {
SignerInfo signerInfo = new SignerInfo(
new X500Name(issuerName),
signerEntry.cert.getSerialNumber(),
AlgorithmId.get(
AlgorithmId.getDigAlgFromSigAlg(sigAlgo)),
SignatureUtil.getDigestAlgInPkcs7SignerInfo(
signature, sigAlgo, signerEntry.privateKey, false),
AlgorithmId.get(sigAlgo),
signature.sign());