final boolean isRootCA = certProfile.getType()==CertificateProfile.TYPE_ROOTCA;
// Get certificate validity time notBefore and notAfter
final CertificateValidity val = new CertificateValidity(subject, certProfile, notBefore, notAfter, cacert, isRootCA);
final X509V3CertificateGenerator certgen = new X509V3CertificateGenerator();
{
// Serialnumber is either random bits, where random generator is initialized by the serno generator.
// Or a custom serial number defined in the end entity object
final ExtendedInformation ei = subject.getExtendedinformation();
BigInteger customSN = ei!=null ? ei.certificateSerialNumber() : null;
if (customSN != null) {
if (!certProfile.getAllowCertSerialNumberOverride()) {
final String msg = intres.getLocalizedMessage("signsession.certprof_not_allowing_cert_sn_override_using_normal", customSN.toString(16));
log.info(msg);
customSN = null;
} else {
if (log.isDebugEnabled()) {
log.debug("Using custom serial number: "+customSN.toString(16));
}
}
}
final BigInteger serno = customSN!=null ? customSN : SernoGenerator.instance().getSerno();
certgen.setSerialNumber(serno);
}
certgen.setNotBefore(val.getNotBefore());
certgen.setNotAfter(val.getNotAfter());
certgen.setSignatureAlgorithm(sigAlg);
// Make DNs
if(certProfile.getUseSubjectDNSubSet()){
dn= certProfile.createSubjectDNSubSet(dn);
}
if(certProfile.getUseCNPostfix()){
dn = CertTools.insertCNPostfix(dn,certProfile.getCNPostfix());
}
X509NameEntryConverter converter = null;
if (getUsePrintableStringSubjectDN()) {
converter = new PrintableStringEntryConverter();
} else {
converter = new X509DefaultEntryConverter();
}
// Will we use LDAP DN order (CN first) or X500 DN order (CN last) for the subject DN
boolean ldapdnorder = true;
if ((getUseLdapDNOrder() == false) || (certProfile.getUseLdapDnOrder() == false)) {
ldapdnorder = false;
}
X509Name subjectDNName = CertTools.stringToBcX509Name(dn, converter, ldapdnorder);
if (certProfile.getAllowDNOverride() && (requestX509Name != null) ) {
subjectDNName = requestX509Name;
if (log.isDebugEnabled()) {
log.debug("Using X509Name from request instead of user's registered.");
}
}
if (log.isDebugEnabled()) {
log.debug("Using subjectDN: "+subjectDNName.toString());
}
certgen.setSubjectDN(subjectDNName);
// We must take the issuer DN directly from the CA-certificate otherwise we risk re-ordering the DN
// which many applications do not like.
if (isRootCA) {
// This will be an initial root CA, since no CA-certificate exists
// Or it is a root CA, since the cert is self signed. If it is a root CA we want to use the same encoding for subject and issuer,
// it might have changed over the years.
if (log.isDebugEnabled()) {
log.debug("Using subject DN also as issuer DN, because it is a root CA");
}
certgen.setIssuerDN(subjectDNName);
} else {
javax.security.auth.x500.X500Principal issuerPrincipal = cacert.getSubjectX500Principal();
if (log.isDebugEnabled()) {
log.debug("Using issuer DN directly from the CA certificate: "+issuerPrincipal.getName());
}
certgen.setIssuerDN(issuerPrincipal);
}
certgen.setPublicKey(publicKey);
//
// X509 Certificate Extensions
//
// Extensions we will add to the certificate, later when we have filled the structure with
// everything we want.
X509ExtensionsGenerator extgen = new X509ExtensionsGenerator();
// First we check if there is general extension override, and add all extensions from
// the request in that case
if (certProfile.getAllowExtensionOverride() && extensions!=null) {
Enumeration en = extensions.oids();
while (en!=null && en.hasMoreElements()) {
DERObjectIdentifier oid = (DERObjectIdentifier)en.nextElement();
X509Extension ext = extensions.getExtension(oid);
if (log.isDebugEnabled()) {
log.debug("Overriding extension with oid: "+oid);
}
extgen.addExtension(oid, ext.isCritical(), ext.getValue().getOctets());
}
}
// Second we see if there is Key usage override
X509Extensions overridenexts = extgen.generate();
if (certProfile.getAllowKeyUsageOverride() && (keyusage >= 0)) {
if (log.isDebugEnabled()) {
log.debug("AllowKeyUsageOverride=true. Using KeyUsage from parameter: "+keyusage);
}
if ( (certProfile.getUseKeyUsage() == true) && (keyusage >=0) ){
X509KeyUsage ku = new X509KeyUsage(keyusage);
// We don't want to try to add custom extensions with the same oid if we have already added them
// from the request, if AllowExtensionOverride is enabled.
// Two extensions with the same oid is not allowed in the standard.
if (overridenexts.getExtension(X509Extensions.KeyUsage) == null) {
extgen.addExtension(
X509Extensions.KeyUsage, certProfile.getKeyUsageCritical(), ku);
} else {
if (log.isDebugEnabled()) {
log.debug("KeyUsage was already overridden by an extension, not using KeyUsage from parameter.");
}
}
}
}
// Third, check for standard Certificate Extensions that should be added.
// Standard certificate extensions are defined in CertificateProfile and CertificateExtensionFactory
// and implemented in package org.ejbca.core.model.certextensions.standard
CertificateExtensionFactory fact = CertificateExtensionFactory.getInstance();
List<String> usedStdCertExt = certProfile.getUsedStandardCertificateExtensions();
Iterator<String> certStdExtIter = usedStdCertExt.iterator();
overridenexts = extgen.generate();
while(certStdExtIter.hasNext()){
String oid = certStdExtIter.next();
// We don't want to try to add standard extensions with the same oid if we have already added them
// from the request, if AllowExtensionOverride is enabled.
// Two extensions with the same oid is not allowed in the standard.
if (overridenexts.getExtension(new DERObjectIdentifier(oid)) == null) {
CertificateExtension certExt = fact.getStandardCertificateExtension(oid, certProfile);
if (certExt != null) {
DEREncodable value = certExt.getValue(subject, this, certProfile, publicKey, caPublicKey);
if (value != null) {
extgen.addExtension(new DERObjectIdentifier(certExt.getOID()),certExt.isCriticalFlag(),value);
}
}
} else {
if (log.isDebugEnabled()) {
log.debug("Extension with oid "+oid+" has been overridden, standard extension will not be added.");
}
}
}
// Fourth, check for custom Certificate Extensions that should be added.
// Custom certificate extensions is defined in certextensions.properties
fact = CertificateExtensionFactory.getInstance();
List<Integer> usedCertExt = certProfile.getUsedCertificateExtensions();
Iterator<Integer> certExtIter = usedCertExt.iterator();
while(certExtIter.hasNext()){
Integer id = certExtIter.next();
CertificateExtension certExt = fact.getCertificateExtensions(id);
if (certExt != null) {
// We don't want to try to add custom extensions with the same oid if we have already added them
// from the request, if AllowExtensionOverride is enabled.
// Two extensions with the same oid is not allowed in the standard.
if (overridenexts.getExtension(new DERObjectIdentifier(certExt.getOID())) == null) {
DEREncodable value = certExt.getValue(subject, this, certProfile, publicKey, caPublicKey);
if (value != null) {
extgen.addExtension(new DERObjectIdentifier(certExt.getOID()),certExt.isCriticalFlag(),value);
}
} else {
if (log.isDebugEnabled()) {
log.debug("Extension with oid "+certExt.getOID()+" has been overridden, custom extension will not be added.");
}
}
}
}
// Finally add extensions to certificate generator
X509Extensions exts = extgen.generate();
Enumeration en = exts.oids();
while (en.hasMoreElements()) {
DERObjectIdentifier oid = (DERObjectIdentifier)en.nextElement();
X509Extension ext = exts.getExtension(oid);
certgen.addExtension(oid, ext.isCritical(), ext.getValue().getOctets());
}
//
// End of extensions
//
X509Certificate cert;
if (log.isTraceEnabled()) {
log.trace(">certgen.generate");
}
cert = certgen.generate(caPrivateKey, provider);
if (log.isTraceEnabled()) {
log.trace("<certgen.generate");
}
// Verify before returning