8296901: Do not create unsigned certificate and CRL

Reviewed-by: mullan
This commit is contained in:
Weijun Wang 2022-11-18 02:21:03 +00:00
parent 7b3984cb5a
commit ab6b7ef988
11 changed files with 396 additions and 415 deletions
src/java.base/share/classes/sun/security
test/jdk/sun/security
ec/ed
pkcs/pkcs7
provider/X509Factory
rsa/pss
util/HostnameChecker
x509
X509CRLImpl
X509CertImpl

@ -335,12 +335,11 @@ public final class CertAndKeyGen {
}
if (ext != null) info.setExtensions(ext);
cert = new X509CertImpl(info);
if (signerFlag) {
// use signer's private key to sign
cert.sign(signerPrivateKey, sigAlg);
cert = X509CertImpl.newSigned(info, signerPrivateKey, sigAlg);
} else {
cert.sign(privateKey, sigAlg);
cert = X509CertImpl.newSigned(info, privateKey, sigAlg);
}
return cert;

@ -1536,8 +1536,8 @@ public final class Main {
subjectPubKey,
signerSubjectKeyId);
info.setExtensions(ext);
X509CertImpl cert = new X509CertImpl(info);
cert.sign(privateKey, sigAlgName);
X509CertImpl cert = X509CertImpl
.newSigned(info, privateKey, sigAlgName);
dumpCert(cert, out);
for (Certificate ca: keyStore.getCertificateChain(alias)) {
if (ca instanceof X509Certificate xca) {
@ -1589,8 +1589,9 @@ public final class Main {
badCerts[i] = new X509CRLEntryImpl(new BigInteger(ids.get(i)), firstDate);
}
}
X509CRLImpl crl = new X509CRLImpl(owner, firstDate, lastDate, badCerts);
crl.sign(privateKey, sigAlgName);
X509CRLImpl crl = X509CRLImpl.newSigned(
new X509CRLImpl.TBSCertList(owner, firstDate, lastDate, badCerts),
privateKey, sigAlgName);
if (rfc) {
out.println("-----BEGIN X509 CRL-----");
out.println(Base64.getMimeEncoder(64, CRLF).encodeToString(crl.getEncodedInternal()));
@ -3228,8 +3229,8 @@ public final class Main {
null);
certInfo.setExtensions(ext);
// Sign the new certificate
X509CertImpl newCert = new X509CertImpl(certInfo);
newCert.sign(privKey, sigAlgName);
X509CertImpl newCert = X509CertImpl.newSigned(
certInfo, privKey, sigAlgName);
// Store the new certificate as a single-element certificate chain
keyStore.setKeyEntry(alias, privKey,

@ -26,7 +26,6 @@
package sun.security.x509;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.cert.Certificate;
@ -88,20 +87,262 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
private byte[] tbsCertList = null; // DER encoded "to-be-signed" CRL
private AlgorithmId sigAlgId = null; // sig alg in CRL
// crl information
private int version;
private AlgorithmId infoSigAlgId; // sig alg in "to-be-signed" crl
private X500Name issuer = null;
private X500Principal issuerPrincipal = null;
private Date thisUpdate = null;
private Date nextUpdate = null;
private final Map<X509IssuerSerial,X509CRLEntry> revokedMap =
new TreeMap<>();
private final List<X509CRLEntry> revokedList = new LinkedList<>();
private CRLExtensions extensions = null;
private static final boolean isExplicit = true;
private TBSCertList info;
private boolean readOnly = false;
// crl information
public static class TBSCertList {
private int version;
private AlgorithmId infoSigAlgId; // sig alg in "to-be-signed" crl
private X500Name issuer = null;
private X500Principal issuerPrincipal = null;
private Date thisUpdate = null;
private Date nextUpdate = null;
private final Map<X509IssuerSerial, X509CRLEntry> revokedMap =
new TreeMap<>();
private final List<X509CRLEntry> revokedList = new LinkedList<>();
private CRLExtensions extensions = null;
/**
* Initial TBSCertList constructor, no revoked certs, and no extensions.
*
* @param issuer the name of the CA issuing this CRL.
* @param thisDate the Date of this issue.
* @param nextDate the Date of the next CRL.
*/
public TBSCertList(X500Name issuer, Date thisDate, Date nextDate) {
this.issuer = issuer;
this.thisUpdate = thisDate;
this.nextUpdate = nextDate;
}
/**
* TBSCertList constructor, revoked certs, no extensions.
*
* @param issuer the name of the CA issuing this CRL.
* @param thisDate the Date of this issue.
* @param nextDate the Date of the next CRL.
* @param badCerts the array of CRL entries.
*
* @exception CRLException on parsing/construction errors.
*/
public TBSCertList(X500Name issuer, Date thisDate, Date nextDate,
X509CRLEntry[] badCerts)
throws CRLException
{
this.issuer = issuer;
this.thisUpdate = thisDate;
this.nextUpdate = nextDate;
if (badCerts != null) {
X500Principal crlIssuer = getIssuerX500Principal();
X500Principal badCertIssuer = crlIssuer;
for (int i = 0; i < badCerts.length; i++) {
X509CRLEntryImpl badCert = (X509CRLEntryImpl)badCerts[i];
badCertIssuer = getCertIssuer(badCert, badCertIssuer);
badCert.setCertificateIssuer(crlIssuer, badCertIssuer);
X509IssuerSerial issuerSerial = new X509IssuerSerial
(badCertIssuer, badCert.getSerialNumber());
this.revokedMap.put(issuerSerial, badCert);
this.revokedList.add(badCert);
if (badCert.hasExtensions()) {
this.version = 1;
}
}
}
}
/**
* TBSCertList constructor, revoked certs and extensions.
*
* @param issuer the name of the CA issuing this CRL.
* @param thisDate the Date of this issue.
* @param nextDate the Date of the next CRL.
* @param badCerts the array of CRL entries.
* @param crlExts the CRL extensions.
*
* @exception CRLException on parsing/construction errors.
*/
public TBSCertList(X500Name issuer, Date thisDate, Date nextDate,
X509CRLEntry[] badCerts, CRLExtensions crlExts)
throws CRLException
{
this(issuer, thisDate, nextDate, badCerts);
if (crlExts != null) {
this.extensions = crlExts;
this.version = 1;
}
}
/**
* Constructs from the encoding.
*/
public TBSCertList(DerValue value) throws IOException, CRLException {
if (value.tag != DerValue.tag_Sequence)
throw new CRLException("signed CRL fields invalid");
// parse the information
DerInputStream derStrm = value.data;
DerValue tmp;
byte nextByte;
// version (optional if v1)
version = 0; // by default, version = v1 == 0
nextByte = (byte)derStrm.peekByte();
if (nextByte == DerValue.tag_Integer) {
version = derStrm.getInteger();
if (version != 1) // i.e. v2
throw new CRLException("Invalid version");
}
tmp = derStrm.getDerValue();
// signature
infoSigAlgId = AlgorithmId.parse(tmp);
// issuer
issuer = new X500Name(derStrm);
if (issuer.isEmpty()) {
throw new CRLException("Empty issuer DN not allowed in X509CRLs");
}
// thisUpdate
// check if UTCTime encoded or GeneralizedTime
nextByte = (byte)derStrm.peekByte();
if (nextByte == DerValue.tag_UtcTime) {
thisUpdate = derStrm.getUTCTime();
} else if (nextByte == DerValue.tag_GeneralizedTime) {
thisUpdate = derStrm.getGeneralizedTime();
} else {
throw new CRLException("Invalid encoding for thisUpdate"
+ " (tag=" + nextByte + ")");
}
if (derStrm.available() == 0)
return; // done parsing no more optional fields present
// nextUpdate (optional)
nextByte = (byte)derStrm.peekByte();
if (nextByte == DerValue.tag_UtcTime) {
nextUpdate = derStrm.getUTCTime();
} else if (nextByte == DerValue.tag_GeneralizedTime) {
nextUpdate = derStrm.getGeneralizedTime();
} // else it is not present
if (derStrm.available() == 0)
return; // done parsing no more optional fields present
// revokedCertificates (optional)
nextByte = (byte)derStrm.peekByte();
if ((nextByte == DerValue.tag_SequenceOf)
&& (! ((nextByte & 0x0c0) == 0x080))) {
DerValue[] badCerts = derStrm.getSequence(4);
X500Principal crlIssuer = getIssuerX500Principal();
X500Principal badCertIssuer = crlIssuer;
for (int i = 0; i < badCerts.length; i++) {
X509CRLEntryImpl entry = new X509CRLEntryImpl(badCerts[i]);
badCertIssuer = getCertIssuer(entry, badCertIssuer);
entry.setCertificateIssuer(crlIssuer, badCertIssuer);
X509IssuerSerial issuerSerial = new X509IssuerSerial
(badCertIssuer, entry.getSerialNumber());
revokedMap.put(issuerSerial, entry);
revokedList.add(entry);
}
}
if (derStrm.available() == 0)
return; // done parsing no extensions
// crlExtensions (optional)
tmp = derStrm.getDerValue();
if (tmp.isConstructed() && tmp.isContextSpecific((byte)0)) {
extensions = new CRLExtensions(tmp.data);
}
}
/**
* Return the issuer as X500Principal.
*/
public X500Principal getIssuerX500Principal() {
if (issuerPrincipal == null) {
issuerPrincipal = issuer.asX500Principal();
}
return issuerPrincipal;
}
/**
* Returns the X500 certificate issuer DN of a CRL entry.
*
* @param entry the entry to check
* @param prevCertIssuer the previous entry's certificate issuer
* @return the X500Principal in a CertificateIssuerExtension, or
* prevCertIssuer if it does not exist
*/
private X500Principal getCertIssuer(X509CRLEntryImpl entry,
X500Principal prevCertIssuer) {
CertificateIssuerExtension ciExt =
entry.getCertificateIssuerExtension();
if (ciExt != null) {
GeneralNames names = ciExt.getNames();
X500Name issuerDN = (X500Name) names.get(0).getName();
return issuerDN.asX500Principal();
} else {
return prevCertIssuer;
}
}
/**
* Encodes the "to-be-signed" TBSCertList to the OutputStream.
*
* @exception CRLException on encoding errors.
*/
public byte[] encodeInfo() throws CRLException {
try {
DerOutputStream tmp = new DerOutputStream();
DerOutputStream rCerts = new DerOutputStream();
DerOutputStream seq = new DerOutputStream();
if (version != 0) // v2 crl encode version
tmp.putInteger(version);
infoSigAlgId.encode(tmp);
if ((version == 0) && (issuer.toString() == null))
throw new CRLException("Null Issuer DN not allowed in v1 CRL");
issuer.encode(tmp);
if (thisUpdate.getTime() < CertificateValidity.YR_2050)
tmp.putUTCTime(thisUpdate);
else
tmp.putGeneralizedTime(thisUpdate);
if (nextUpdate != null) {
if (nextUpdate.getTime() < CertificateValidity.YR_2050)
tmp.putUTCTime(nextUpdate);
else
tmp.putGeneralizedTime(nextUpdate);
}
if (!revokedList.isEmpty()) {
for (X509CRLEntry entry : revokedList) {
((X509CRLEntryImpl)entry).encode(rCerts);
}
tmp.write(DerValue.tag_Sequence, rCerts);
}
if (extensions != null)
extensions.encode(tmp, isExplicit);
seq.write(DerValue.tag_Sequence, tmp);
return seq.toByteArray();
} catch (IOException e) {
throw new CRLException("Encoding error: " + e.getMessage());
}
}
}
private static final boolean isExplicit = true;
/**
* PublicKey that has previously been used to successfully verify
@ -117,10 +358,17 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
private String verifiedProvider;
/**
* Not to be used. As it would lead to cases of uninitialized
* CRL objects.
* Constructor simply setting all (non-cache) fields. Only used in
* {@link #newSigned}.
*/
private X509CRLImpl() { }
public X509CRLImpl(TBSCertList info, AlgorithmId sigAlgId, byte[] signature,
byte[] tbsCertList, byte[] signedCRL) {
this.info = info;
this.sigAlgId = sigAlgId;
this.signature = signature;
this.tbsCertList = tbsCertList;
this.signedCRL = Objects.requireNonNull(signedCRL);
}
/**
* Unmarshals an X.509 CRL from its encoded form, parsing the encoded
@ -136,7 +384,6 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
try {
parse(new DerValue(crlData));
} catch (IOException e) {
signedCRL = null;
throw new CRLException("Parsing error: " + e.getMessage());
}
}
@ -151,7 +398,6 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
try {
parse(val);
} catch (IOException e) {
signedCRL = null;
throw new CRLException("Parsing error: " + e.getMessage());
}
}
@ -167,79 +413,12 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
try {
parse(new DerValue(inStrm));
} catch (IOException e) {
signedCRL = null;
throw new CRLException("Parsing error: " + e.getMessage());
}
}
/**
* Initial CRL constructor, no revoked certs, and no extensions.
*
* @param issuer the name of the CA issuing this CRL.
* @param thisDate the Date of this issue.
* @param nextDate the Date of the next CRL.
*/
public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate) {
this.issuer = issuer;
this.thisUpdate = thisDate;
this.nextUpdate = nextDate;
}
/**
* CRL constructor, revoked certs, no extensions.
*
* @param issuer the name of the CA issuing this CRL.
* @param thisDate the Date of this issue.
* @param nextDate the Date of the next CRL.
* @param badCerts the array of CRL entries.
*
* @exception CRLException on parsing/construction errors.
*/
public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate,
X509CRLEntry[] badCerts)
throws CRLException
{
this.issuer = issuer;
this.thisUpdate = thisDate;
this.nextUpdate = nextDate;
if (badCerts != null) {
X500Principal crlIssuer = getIssuerX500Principal();
X500Principal badCertIssuer = crlIssuer;
for (int i = 0; i < badCerts.length; i++) {
X509CRLEntryImpl badCert = (X509CRLEntryImpl)badCerts[i];
badCertIssuer = getCertIssuer(badCert, badCertIssuer);
badCert.setCertificateIssuer(crlIssuer, badCertIssuer);
X509IssuerSerial issuerSerial = new X509IssuerSerial
(badCertIssuer, badCert.getSerialNumber());
this.revokedMap.put(issuerSerial, badCert);
this.revokedList.add(badCert);
if (badCert.hasExtensions()) {
this.version = 1;
}
}
}
}
/**
* CRL constructor, revoked certs and extensions.
*
* @param issuer the name of the CA issuing this CRL.
* @param thisDate the Date of this issue.
* @param nextDate the Date of the next CRL.
* @param badCerts the array of CRL entries.
* @param crlExts the CRL extensions.
*
* @exception CRLException on parsing/construction errors.
*/
public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate,
X509CRLEntry[] badCerts, CRLExtensions crlExts)
throws CRLException
{
this(issuer, thisDate, nextDate, badCerts);
if (crlExts != null) {
this.extensions = crlExts;
this.version = 1;
}
public TBSCertList info() {
return info;
}
/**
@ -248,9 +427,6 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* code.
*/
public byte[] getEncodedInternal() throws CRLException {
if (signedCRL == null) {
throw new CRLException("Null CRL to encode");
}
return signedCRL;
}
@ -263,56 +439,6 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
return getEncodedInternal().clone();
}
/**
* Encodes the "to-be-signed" CRL to the OutputStream.
*
* @param out the OutputStream to write to.
* @exception CRLException on encoding errors.
*/
public void encodeInfo(OutputStream out) throws CRLException {
try {
DerOutputStream tmp = new DerOutputStream();
DerOutputStream rCerts = new DerOutputStream();
DerOutputStream seq = new DerOutputStream();
if (version != 0) // v2 crl encode version
tmp.putInteger(version);
infoSigAlgId.encode(tmp);
if ((version == 0) && (issuer.toString() == null))
throw new CRLException("Null Issuer DN not allowed in v1 CRL");
issuer.encode(tmp);
if (thisUpdate.getTime() < CertificateValidity.YR_2050)
tmp.putUTCTime(thisUpdate);
else
tmp.putGeneralizedTime(thisUpdate);
if (nextUpdate != null) {
if (nextUpdate.getTime() < CertificateValidity.YR_2050)
tmp.putUTCTime(nextUpdate);
else
tmp.putGeneralizedTime(nextUpdate);
}
if (!revokedList.isEmpty()) {
for (X509CRLEntry entry : revokedList) {
((X509CRLEntryImpl)entry).encode(rCerts);
}
tmp.write(DerValue.tag_Sequence, rCerts);
}
if (extensions != null)
extensions.encode(tmp, isExplicit);
seq.write(DerValue.tag_Sequence, tmp);
tbsCertList = seq.toByteArray();
out.write(tbsCertList);
} catch (IOException e) {
throw new CRLException("Encoding error: " + e.getMessage());
}
}
/**
* Verifies that this CRL was signed using the
* private key that corresponds to the given public key.
@ -362,9 +488,6 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
return;
}
}
if (signedCRL == null) {
throw new CRLException("Uninitialized CRL");
}
Signature sigVerf;
String sigName = sigAlgId.getName();
if (sigProvider.isEmpty()) {
@ -415,9 +538,6 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
SignatureException {
if (signedCRL == null) {
throw new CRLException("Uninitialized CRL");
}
Signature sigVerf;
String sigName = sigAlgId.getName();
if (sigProvider == null) {
@ -448,10 +568,12 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
}
/**
* Encodes an X.509 CRL, and signs it using the given key.
* Creates a new X.509 CRL, which is signed using the given key.
*
* @param info the TBSCertList to sign
* @param key the private key used for signing.
* @param algorithm the name of the signature algorithm used.
* @return a newly signed CRL
*
* @exception NoSuchAlgorithmException on unsupported signature algorithms.
* @exception InvalidKeyException on incorrect key.
@ -459,18 +581,20 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* @exception SignatureException on signature errors.
* @exception CRLException if any mandatory data was omitted.
*/
public void sign(PrivateKey key, String algorithm)
public static X509CRLImpl newSigned(TBSCertList info, PrivateKey key, String algorithm)
throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
NoSuchProviderException, SignatureException {
sign(key, algorithm, null);
return newSigned(info, key, algorithm, null);
}
/**
* Encodes an X.509 CRL, and signs it using the given key.
* Creates a new X.509 CRL, which is signed using the given key.
*
* @param info the TBSCertList to sign
* @param key the private key used for signing.
* @param algorithm the name of the signature algorithm used.
* @param provider (optional) the name of the provider.
* @return a newly signed CRL
*
* @exception NoSuchAlgorithmException on unsupported signature algorithms.
* @exception InvalidKeyException on incorrect key.
@ -478,36 +602,35 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* @exception SignatureException on signature errors.
* @exception CRLException if any mandatory data was omitted.
*/
public void sign(PrivateKey key, String algorithm, String provider)
public static X509CRLImpl newSigned(TBSCertList info, PrivateKey key, String algorithm, String provider)
throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
NoSuchProviderException, SignatureException {
try {
if (readOnly)
throw new CRLException("cannot over-write existing CRL");
Signature sigEngine = SignatureUtil.fromKey(algorithm, key, provider);
sigAlgId = SignatureUtil.fromSignature(sigEngine, key);
infoSigAlgId = sigAlgId;
AlgorithmId sigAlgId = SignatureUtil.fromSignature(sigEngine, key);
info.infoSigAlgId = sigAlgId;
DerOutputStream out = new DerOutputStream();
DerOutputStream tmp = new DerOutputStream();
// encode crl info
encodeInfo(tmp);
byte[] tbsCertList = info.encodeInfo();
tmp.writeBytes(tbsCertList);
// encode algorithm identifier
sigAlgId.encode(tmp);
// Create and encode the signature itself.
sigEngine.update(tbsCertList, 0, tbsCertList.length);
signature = sigEngine.sign();
byte[] signature = sigEngine.sign();
tmp.putBitString(signature);
// Wrap the signed data in a SEQUENCE { data, algorithm, sig }
out.write(DerValue.tag_Sequence, tmp);
signedCRL = out.toByteArray();
readOnly = true;
byte[] signedCRL = out.toByteArray();
return new X509CRLImpl(info, sigAlgId, signature,
tbsCertList, signedCRL);
} catch (IOException e) {
throw new CRLException("Error while encoding data: " +
e.getMessage());
@ -527,7 +650,7 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
public String toStringWithAlgName(String name) {
StringBuilder sb = new StringBuilder();
sb.append("X.509 CRL v")
.append(version+1)
.append(info.version+1)
.append('\n');
if (sigAlgId != null)
sb.append("Signature Algorithm: ")
@ -535,33 +658,33 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
.append(", OID=")
.append(sigAlgId.getOID())
.append('\n');
if (issuer != null)
if (info.issuer != null)
sb.append("Issuer: ")
.append(issuer)
.append(info.issuer)
.append('\n');
if (thisUpdate != null)
if (info.thisUpdate != null)
sb.append("\nThis Update: ")
.append(thisUpdate)
.append(info.thisUpdate)
.append('\n');
if (nextUpdate != null)
if (info.nextUpdate != null)
sb.append("Next Update: ")
.append(nextUpdate)
.append(info.nextUpdate)
.append('\n');
if (revokedList.isEmpty())
if (info.revokedList.isEmpty())
sb.append("\nNO certificates have been revoked\n");
else {
sb.append("\nRevoked Certificates: ")
.append(revokedList.size());
.append(info.revokedList.size());
int i = 1;
for (X509CRLEntry entry: revokedList) {
for (X509CRLEntry entry: info.revokedList) {
sb.append("\n[")
.append(i++)
.append("] ")
.append(entry);
}
}
if (extensions != null) {
Collection<Extension> allExts = extensions.getAllExtensions();
if (info.extensions != null) {
Collection<Extension> allExts = info.extensions.getAllExtensions();
Object[] objs = allExts.toArray();
sb.append("\nCRL Extensions: ")
.append(objs.length);
@ -609,12 +732,12 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* false otherwise.
*/
public boolean isRevoked(Certificate cert) {
if (revokedMap.isEmpty() ||
if (info.revokedMap.isEmpty() ||
(!(cert instanceof X509Certificate xcert))) {
return false;
}
X509IssuerSerial issuerSerial = new X509IssuerSerial(xcert);
return revokedMap.containsKey(issuerSerial);
return info.revokedMap.containsKey(issuerSerial);
}
/**
@ -628,7 +751,7 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* @return the version number, i.e. 1 or 2.
*/
public int getVersion() {
return version+1;
return info.version+1;
}
/**
@ -661,7 +784,7 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
*/
@SuppressWarnings("deprecation")
public Principal getIssuerDN() {
return issuer;
return info.issuer;
}
/**
@ -669,10 +792,7 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* to provide a slightly more efficient version.
*/
public X500Principal getIssuerX500Principal() {
if (issuerPrincipal == null) {
issuerPrincipal = issuer.asX500Principal();
}
return issuerPrincipal;
return info.getIssuerX500Principal();
}
/**
@ -682,7 +802,7 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* @return the thisUpdate date from the CRL.
*/
public Date getThisUpdate() {
return new Date(thisUpdate.getTime());
return new Date(info.thisUpdate.getTime());
}
/**
@ -692,9 +812,9 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* not present.
*/
public Date getNextUpdate() {
if (nextUpdate == null)
if (info.nextUpdate == null)
return null;
return new Date(nextUpdate.getTime());
return new Date(info.nextUpdate.getTime());
}
/**
@ -705,24 +825,24 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* @see X509CRLEntry
*/
public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) {
if (revokedMap.isEmpty()) {
if (info.revokedMap.isEmpty()) {
return null;
}
// assume this is a direct CRL entry (cert and CRL issuer are the same)
X509IssuerSerial issuerSerial = new X509IssuerSerial
(getIssuerX500Principal(), serialNumber);
return revokedMap.get(issuerSerial);
return info.revokedMap.get(issuerSerial);
}
/**
* Gets the CRL entry for the given certificate.
*/
public X509CRLEntry getRevokedCertificate(X509Certificate cert) {
if (revokedMap.isEmpty()) {
if (info.revokedMap.isEmpty()) {
return null;
}
X509IssuerSerial issuerSerial = new X509IssuerSerial(cert);
return revokedMap.get(issuerSerial);
return info.revokedMap.get(issuerSerial);
}
/**
@ -734,10 +854,10 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* @see X509CRLEntry
*/
public Set<X509CRLEntry> getRevokedCertificates() {
if (revokedList.isEmpty()) {
if (info.revokedList.isEmpty()) {
return null;
} else {
return new TreeSet<>(revokedList);
return new TreeSet<>(info.revokedList);
}
}
@ -929,9 +1049,9 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* not supported, otherwise return false.
*/
public boolean hasUnsupportedCriticalExtension() {
if (extensions == null)
if (info.extensions == null)
return false;
return extensions.hasUnsupportedCriticalExtension();
return info.extensions.hasUnsupportedCriticalExtension();
}
/**
@ -943,11 +1063,11 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* CRL that are marked critical.
*/
public Set<String> getCriticalExtensionOIDs() {
if (extensions == null) {
if (info.extensions == null) {
return null;
}
Set<String> extSet = new TreeSet<>();
for (Extension ex : extensions.getAllExtensions()) {
for (Extension ex : info.extensions.getAllExtensions()) {
if (ex.isCritical()) {
extSet.add(ex.getExtensionId().toString());
}
@ -964,11 +1084,11 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* CRL that are NOT marked critical.
*/
public Set<String> getNonCriticalExtensionOIDs() {
if (extensions == null) {
if (info.extensions == null) {
return null;
}
Set<String> extSet = new TreeSet<>();
for (Extension ex : extensions.getAllExtensions()) {
for (Extension ex : info.extensions.getAllExtensions()) {
if (!ex.isCritical()) {
extSet.add(ex.getExtensionId().toString());
}
@ -988,7 +1108,7 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* @return the der encoded octet string of the extension value.
*/
public byte[] getExtensionValue(String oid) {
if (extensions == null)
if (info.extensions == null)
return null;
try {
String extAlias = OIDMap.getName(ObjectIdentifier.of(oid));
@ -996,7 +1116,7 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
if (extAlias == null) { // may be unknown
ObjectIdentifier findOID = ObjectIdentifier.of(oid);
for (Extension ex : extensions.getAllExtensions()) {
for (Extension ex : info.extensions.getAllExtensions()) {
ObjectIdentifier inCertOID = ex.getExtensionId();
if (inCertOID.equals(findOID)) {
crlExt = ex;
@ -1004,7 +1124,7 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
}
}
} else
crlExt = extensions.getExtension(extAlias);
crlExt = info.extensions.getExtension(extAlias);
if (crlExt == null)
return null;
byte[] extData = crlExt.getExtensionValue();
@ -1025,20 +1145,17 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* @return Object of type {@code <extension>} or null, if not found
*/
public Object getExtension(ObjectIdentifier oid) {
if (extensions == null)
if (info.extensions == null)
return null;
// XXX Consider cloning this
return extensions.getExtension(OIDMap.getName(oid));
return info.extensions.getExtension(OIDMap.getName(oid));
}
/*
* Parses an X.509 CRL, should be used only by constructors.
*/
private void parse(DerValue val) throws CRLException, IOException {
// check if we can overwrite the certificate
if (readOnly)
throw new CRLException("cannot over-write existing CRL");
if ( val.getData() == null || val.tag != DerValue.tag_Sequence)
throw new CRLException("Invalid DER-encoded CRL data");
@ -1054,10 +1171,14 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
throw new CRLException("signed overrun, bytes = "
+ val.data.available());
if (seq[0].tag != DerValue.tag_Sequence)
throw new CRLException("signed CRL fields invalid");
info = new TBSCertList(seq[0]);
sigAlgId = AlgorithmId.parse(seq[1]);
// the "inner" and "outer" signature algorithms must match
if (!sigAlgId.equals(info.infoSigAlgId)) {
throw new CRLException("Signature algorithm mismatch");
}
signature = seq[2].getBitString();
if (seq[1].data.available() != 0)
@ -1069,90 +1190,7 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
// the tbsCertsList
tbsCertList = seq[0].toByteArray();
// parse the information
DerInputStream derStrm = seq[0].data;
DerValue tmp;
byte nextByte;
// version (optional if v1)
version = 0; // by default, version = v1 == 0
nextByte = (byte)derStrm.peekByte();
if (nextByte == DerValue.tag_Integer) {
version = derStrm.getInteger();
if (version != 1) // i.e. v2
throw new CRLException("Invalid version");
}
tmp = derStrm.getDerValue();
// signature
AlgorithmId tmpId = AlgorithmId.parse(tmp);
// the "inner" and "outer" signature algorithms must match
if (! tmpId.equals(sigAlgId))
throw new CRLException("Signature algorithm mismatch");
infoSigAlgId = tmpId;
// issuer
issuer = new X500Name(derStrm);
if (issuer.isEmpty()) {
throw new CRLException("Empty issuer DN not allowed in X509CRLs");
}
// thisUpdate
// check if UTCTime encoded or GeneralizedTime
nextByte = (byte)derStrm.peekByte();
if (nextByte == DerValue.tag_UtcTime) {
thisUpdate = derStrm.getUTCTime();
} else if (nextByte == DerValue.tag_GeneralizedTime) {
thisUpdate = derStrm.getGeneralizedTime();
} else {
throw new CRLException("Invalid encoding for thisUpdate"
+ " (tag=" + nextByte + ")");
}
if (derStrm.available() == 0)
return; // done parsing no more optional fields present
// nextUpdate (optional)
nextByte = (byte)derStrm.peekByte();
if (nextByte == DerValue.tag_UtcTime) {
nextUpdate = derStrm.getUTCTime();
} else if (nextByte == DerValue.tag_GeneralizedTime) {
nextUpdate = derStrm.getGeneralizedTime();
} // else it is not present
if (derStrm.available() == 0)
return; // done parsing no more optional fields present
// revokedCertificates (optional)
nextByte = (byte)derStrm.peekByte();
if ((nextByte == DerValue.tag_SequenceOf)
&& (! ((nextByte & 0x0c0) == 0x080))) {
DerValue[] badCerts = derStrm.getSequence(4);
X500Principal crlIssuer = getIssuerX500Principal();
X500Principal badCertIssuer = crlIssuer;
for (int i = 0; i < badCerts.length; i++) {
X509CRLEntryImpl entry = new X509CRLEntryImpl(badCerts[i]);
badCertIssuer = getCertIssuer(entry, badCertIssuer);
entry.setCertificateIssuer(crlIssuer, badCertIssuer);
X509IssuerSerial issuerSerial = new X509IssuerSerial
(badCertIssuer, entry.getSerialNumber());
revokedMap.put(issuerSerial, entry);
revokedList.add(entry);
}
}
if (derStrm.available() == 0)
return; // done parsing no extensions
// crlExtensions (optional)
tmp = derStrm.getDerValue();
if (tmp.isConstructed() && tmp.isContextSpecific((byte)0)) {
extensions = new CRLExtensions(tmp.data);
}
readOnly = true;
}
/**
@ -1212,32 +1250,8 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
}
}
/**
* Returns the X500 certificate issuer DN of a CRL entry.
*
* @param entry the entry to check
* @param prevCertIssuer the previous entry's certificate issuer
* @return the X500Principal in a CertificateIssuerExtension, or
* prevCertIssuer if it does not exist
*/
private X500Principal getCertIssuer(X509CRLEntryImpl entry,
X500Principal prevCertIssuer) {
CertificateIssuerExtension ciExt =
entry.getCertificateIssuerExtension();
if (ciExt != null) {
GeneralNames names = ciExt.getNames();
X500Name issuerDN = (X500Name) names.get(0).getName();
return issuerDN.asX500Principal();
} else {
return prevCertIssuer;
}
}
@Override
public void encode(DerOutputStream out) throws IOException {
if (signedCRL == null)
throw new IOException("Null CRL to encode");
out.write(signedCRL.clone());
}

@ -25,12 +25,7 @@
package sun.security.x509;
import java.io.BufferedReader;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.*;
@ -79,10 +74,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
public static final String NAME = "x509";
// when we sign and decode we set this to true
// this is our means to make certificates immutable
private boolean readOnly = false;
// Certificate data, and its envelope
private byte[] signedCert = null;
protected X509CertInfo info = null;
@ -124,9 +115,16 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
private boolean verificationResult;
/**
* Default constructor.
* Constructor simply setting all (non-cache) fields. Only used in
* {@link #newSigned}.
*/
public X509CertImpl() { }
public X509CertImpl(X509CertInfo info, AlgorithmId algId, byte[] signature,
byte[] signedCert) {
this.info = info;
this.algId = algId;
this.signature = signature;
this.signedCert = Objects.requireNonNull(signedCert);
}
/**
* Unmarshals a certificate from its encoded form, parsing the
@ -144,13 +142,28 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
try {
parse(new DerValue(certData));
} catch (IOException e) {
signedCert = null;
throw new CertificateException("Unable to initialize, " + e, e);
}
}
/**
* unmarshals an X.509 certificate from an input stream. If the
* Unmarshals a certificate from its encoded form, parsing a DER value.
* This form of constructor is used by agents which need to examine
* and use certificate contents.
*
* @param derVal the der value containing the encoded cert.
* @exception CertificateException on parsing and initialization errors.
*/
public X509CertImpl(DerValue derVal) throws CertificateException {
try {
parse(derVal);
} catch (IOException e) {
throw new CertificateException("Unable to initialize, " + e, e);
}
}
/**
* Unmarshals an X.509 certificate from an input stream. If the
* certificate is RFC1421 hex-encoded, then it must begin with
* the line X509Factory.BEGIN_CERT and end with the line
* X509Factory.END_CERT.
@ -235,37 +248,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
return der;
}
/**
* 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.
*/
public X509CertImpl(X509CertInfo certInfo) {
this.info = certInfo;
}
/**
* Unmarshal a certificate from its encoded form, parsing a DER value.
* This form of constructor is used by agents which need to examine
* and use certificate contents.
*
* @param derVal the der value containing the encoded cert.
* @exception CertificateException on parsing and initialization errors.
*/
public X509CertImpl(DerValue derVal) throws CertificateException {
try {
parse(derVal);
} catch (IOException e) {
signedCert = null;
throw new CertificateException("Unable to initialize, " + e, e);
}
}
// helper method to record certificate, if necessary, after construction
public static X509CertImpl newX509CertImpl(byte[] certData) throws CertificateException {
var cert = new X509CertImpl(certData);
@ -283,8 +265,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
*/
@Override
public void encode(DerOutputStream out) throws IOException {
if (signedCert == null)
throw new IOException("Null certificate to encode");
out.write(signedCert.clone());
}
@ -306,10 +286,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
* code.
*/
public byte[] getEncodedInternal() throws CertificateEncodingException {
if (signedCert == null) {
throw new CertificateEncodingException(
"Null certificate to encode");
}
return signedCert;
}
@ -367,9 +343,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
}
}
}
if (signedCert == null) {
throw new CertificateEncodingException("Uninitialized certificate");
}
// Verify the signature ...
Signature sigVerf;
String sigName = algId.getName();
@ -421,9 +394,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
public synchronized void verify(PublicKey key, Provider sigProvider)
throws CertificateException, NoSuchAlgorithmException,
InvalidKeyException, SignatureException {
if (signedCert == null) {
throw new CertificateEncodingException("Uninitialized certificate");
}
// Verify the signature ...
Signature sigVerf;
String sigName = algId.getName();
@ -455,13 +425,15 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
}
/**
* Creates an X.509 certificate, and signs it using the given key
* Creates a new X.509 certificate, which is signed using the given key
* (associating a signature algorithm and an X.500 name).
* This operation is used to implement the certificate generation
* functionality of a certificate authority.
*
* @param info the X509CertInfo to sign
* @param key the private key used for signing.
* @param algorithm the name of the signature algorithm used.
* @return the newly signed certificate
*
* @exception InvalidKeyException on incorrect key.
* @exception NoSuchAlgorithmException on unsupported signature algorithms.
@ -469,21 +441,23 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
* @exception SignatureException on signature errors.
* @exception CertificateException on encoding errors.
*/
public void sign(PrivateKey key, String algorithm)
public static X509CertImpl newSigned(X509CertInfo info, PrivateKey key, String algorithm)
throws CertificateException, NoSuchAlgorithmException,
InvalidKeyException, NoSuchProviderException, SignatureException {
sign(key, algorithm, null);
return newSigned(info, key, algorithm, null);
}
/**
* Creates an X.509 certificate, and signs it using the given key
* Creates a new X.509 certificate, which is signed using the given key
* (associating a signature algorithm and an X.500 name).
* This operation is used to implement the certificate generation
* functionality of a certificate authority.
*
* @param info the X509CertInfo to sign
* @param key the private key used for signing.
* @param algorithm the name of the signature algorithm used.
* @param provider (optional) the name of the provider.
* @return the newly signed certificate
*
* @exception NoSuchAlgorithmException on unsupported signature algorithms.
* @exception InvalidKeyException on incorrect key.
@ -491,17 +465,13 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
* @exception SignatureException on signature errors.
* @exception CertificateException on encoding errors.
*/
public void sign(PrivateKey key, String algorithm, String provider)
public static X509CertImpl newSigned(X509CertInfo info, PrivateKey key, String algorithm, String provider)
throws CertificateException, NoSuchAlgorithmException,
InvalidKeyException, NoSuchProviderException, SignatureException {
try {
if (readOnly) {
throw new CertificateEncodingException(
"cannot over-write existing certificate");
}
Signature sigEngine = SignatureUtil.fromKey(
algorithm, key, provider);
algId = SignatureUtil.fromSignature(sigEngine, key);
AlgorithmId algId = SignatureUtil.fromSignature(sigEngine, key);
DerOutputStream out = new DerOutputStream();
DerOutputStream tmp = new DerOutputStream();
@ -516,14 +486,14 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
// Create and encode the signature itself.
sigEngine.update(rawCert, 0, rawCert.length);
signature = sigEngine.sign();
byte[] signature = sigEngine.sign();
tmp.putBitString(signature);
// Wrap the signed data in a SEQUENCE { data, algorithm, sig }
out.write(DerValue.tag_Sequence, tmp);
signedCert = out.toByteArray();
readOnly = true;
byte[] signedCert = out.toByteArray();
return new X509CertImpl(info, algId, signature, signedCert);
} catch (IOException e) {
throw new CertificateEncodingException(e.toString());
}
@ -1160,7 +1130,7 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
@Override
public synchronized List<String> getExtendedKeyUsage()
throws CertificateParsingException {
if (readOnly && extKeyUsage != null) {
if (extKeyUsage != null) {
return extKeyUsage;
}
ExtendedKeyUsageExtension ext = (ExtendedKeyUsageExtension)
@ -1351,7 +1321,7 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
public synchronized Collection<List<?>> getSubjectAlternativeNames()
throws CertificateParsingException {
// return cached value if we can
if (readOnly && subjectAlternativeNames != null) {
if (subjectAlternativeNames != null) {
return cloneAltNames(subjectAlternativeNames);
}
SubjectAlternativeNameExtension subjectAltNameExt =
@ -1403,7 +1373,7 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
public synchronized Collection<List<?>> getIssuerAlternativeNames()
throws CertificateParsingException {
// return cached value if we can
if (readOnly && issuerAlternativeNames != null) {
if (issuerAlternativeNames != null) {
return cloneAltNames(issuerAlternativeNames);
}
IssuerAlternativeNameExtension issuerAltNameExt =
@ -1463,11 +1433,8 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
* parts away for later verification.
*/
private void parse(DerValue val)
throws CertificateException, IOException {
throws CertificateException, IOException {
// check if we can overwrite the certificate
if (readOnly)
throw new CertificateParsingException(
"cannot over-write existing certificate");
if (val.data == null || val.tag != DerValue.tag_Sequence)
throw new CertificateParsingException(
@ -1504,7 +1471,6 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
AlgorithmId infoSigAlg = info.getAlgorithmId().getAlgId();
if (! algId.equals(infoSigAlg))
throw new CertificateException("Signature algorithm mismatch");
readOnly = true;
}
/**

@ -79,9 +79,10 @@ public class EdCRLSign {
System.out.printf("Case Algo:%s, Param:%s, Intitiate with random:%s%n",
name, param, initWithRandom);
KeyPair kp = genKeyPair(provider, name, param, initWithRandom);
X509CRLImpl crl = new X509CRLImpl(
new X500Name("CN=Issuer"), new Date(), new Date());
crl.sign(kp.getPrivate(), name);
X509CRLImpl crl = X509CRLImpl.newSigned(
new X509CRLImpl.TBSCertList(new X500Name("CN=Issuer"),
new Date(), new Date()),
kp.getPrivate(), name);
crl.verify(kp.getPublic());
System.out.println("Passed.");
}

@ -254,8 +254,7 @@ class SimpleSigner {
info.setValidity(interval);
info.setIssuer(agent);
certLocal = new X509CertImpl(info);
certLocal.sign(privateKey, algId.getName());
certLocal = X509CertImpl.newSigned(info, privateKey, algId.getName());
return certLocal;
}

@ -69,8 +69,9 @@ public class BigCRL {
badCerts[i] = new X509CRLEntryImpl(
BigInteger.valueOf(i), date, ext);
}
X509CRLImpl crl = new X509CRLImpl(owner, date, date, badCerts);
crl.sign(privateKey, sigAlgName);
X509CRLImpl crl = X509CRLImpl.newSigned(
new X509CRLImpl.TBSCertList(owner, date, date, badCerts),
privateKey, sigAlgName);
byte[] data = crl.getEncodedInternal();
// Make sure the CRL is big enough

@ -49,8 +49,8 @@ public class DefaultParamSpec {
new MGF1ParameterSpec("SHA-384"),
48, PSSParameterSpec.TRAILER_FIELD_BC)));
X509CRLImpl crl = new X509CRLImpl(
new X500Name("CN=Issuer"), new Date(), new Date());
crl.sign(kpg.generateKeyPair().getPrivate(), "RSASSA-PSS");
X509CRLImpl crl = X509CRLImpl.newSigned(
new X509CRLImpl.TBSCertList(new X500Name("CN=Issuer"), new Date(), new Date()),
kpg.generateKeyPair().getPrivate(), "RSASSA-PSS");
}
}

@ -225,7 +225,7 @@ public class TestHostnameChecker {
}
private static X509Certificate mock(String domain) {
return new X509CertImpl() {
return new X509CertImpl(null, null, null, new byte[0]) {
@Override
public Collection<List<?>> getSubjectAlternativeNames() {
return List.of(List.of(2, domain));

@ -55,9 +55,10 @@ public class OrderAndDup {
new Date(System.currentTimeMillis()+i*1000));
}
X500Name owner = new X500Name("CN=CA");
X509CRLImpl crl = new X509CRLImpl(owner, new Date(), new Date(), badCerts);
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
crl.sign(kpg.genKeyPair().getPrivate(), "SHA1withRSA");
X509CRLImpl crl = X509CRLImpl.newSigned(
new X509CRLImpl.TBSCertList(owner, new Date(), new Date(), badCerts),
kpg.genKeyPair().getPrivate(), "SHA1withRSA");
byte[] data = crl.getEncodedInternal();
// Check the encoding

@ -205,8 +205,7 @@ public class V3Certificate {
cert.setExtensions(exts);
// Generate and sign X509CertImpl
X509CertImpl crt = new X509CertImpl(cert);
crt.sign(privateKey, sigAlg);
X509CertImpl crt = X509CertImpl.newSigned(cert, privateKey, sigAlg);
crt.verify(publicKey);
try (FileOutputStream fos = new FileOutputStream(new File(V3_FILE));