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());
}
}
}
/**