diff options
7 files changed, 207 insertions, 2 deletions
diff --git a/base/common/src/com/netscape/certsrv/system/SystemCertData.java b/base/common/src/com/netscape/certsrv/system/SystemCertData.java index a509e3fb5..064d8e190 100644 --- a/base/common/src/com/netscape/certsrv/system/SystemCertData.java +++ b/base/common/src/com/netscape/certsrv/system/SystemCertData.java @@ -43,6 +43,9 @@ public class SystemCertData { public static final String SUBJECT_DN = "subjectDN"; public static final String CERT = "cert"; public static final String CERT_CHAIN = "certChain"; + public static final String REQUEST_EXT_OID = "req_ext_oid"; + public static final String REQUEST_EXT_CRITICAL = "req_ext_critial"; + public static final String REQUEST_EXT_DATA = "req_ext_data"; @XmlElement protected String tag; @@ -80,6 +83,15 @@ public class SystemCertData { @XmlElement protected String certChain; + @XmlElement + protected String req_ext_oid; + + @XmlElement + protected String req_ext_critical; + + @XmlElement + protected String req_ext_data; + public SystemCertData() { // required for JAXB } @@ -97,6 +109,10 @@ public class SystemCertData { subjectDN = form.getFirst(SUBJECT_DN); cert = form.getFirst(CERT); certChain = form.getFirst(CERT_CHAIN); + //support extension in CSR + req_ext_oid = form.getFirst(REQUEST_EXT_OID); + req_ext_critical = form.getFirst(REQUEST_EXT_CRITICAL); + req_ext_data = form.getFirst(REQUEST_EXT_DATA); } /** @@ -267,4 +283,28 @@ public class SystemCertData { this.certChain = certChain; } + /** + * @return the req_ext_oid + */ + public String getReqExtOID() { + return req_ext_oid; + } + + /** + * @return the req_ext_data + */ + public String getReqExtData() { + return req_ext_data; + } + + /** + * @return the req_ext_critical + */ + public boolean getReqExtCritical() { + if (req_ext_critical.equals("true")) + return true; + else + return false; + } + } diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java index 06728e24b..f44323896 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java +++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java @@ -74,8 +74,14 @@ import netscape.security.pkcs.ContentInfo; import netscape.security.pkcs.PKCS10; import netscape.security.pkcs.PKCS7; import netscape.security.pkcs.SignerInfo; +import netscape.security.util.DerOutputStream; +import netscape.security.util.ObjectIdentifier; import netscape.security.x509.AlgorithmId; +import netscape.security.x509.BasicConstraintsExtension; import netscape.security.x509.CertificateChain; +import netscape.security.x509.Extension; +import netscape.security.x509.Extensions; +import netscape.security.x509.KeyUsageExtension; import netscape.security.x509.X500Name; import netscape.security.x509.X509CertImpl; import netscape.security.x509.X509Key; @@ -2680,9 +2686,11 @@ public class ConfigurationUtils { EBaseException, InvalidKeyException, NotInitializedException, TokenException, NoSuchAlgorithmException, NoSuchProviderException, CertificateException, SignatureException, IOException { + CMS.debug("ConfigurationUtils: handleCertRequest() begins"); // get public key String pubKeyType = config.getString(PCERT_PREFIX + certTag + ".keytype"); String algorithm = config.getString(PCERT_PREFIX + certTag + ".keyalgorithm"); + X509Key pubk = null; if (pubKeyType.equals("rsa")) { pubk = getRSAX509Key(config, certTag); @@ -2713,7 +2721,13 @@ public class ConfigurationUtils { String caDN = config.getString(PCERT_PREFIX + certTag + ".dn"); cert.setDN(caDN); - PKCS10 certReq = CryptoUtil.createCertificationRequest(caDN, pubk, privk, algorithm); + + Extensions exts = null; + if (certTag.equals("signing")) { + CMS.debug("handleCertRequest: certTag is siging -- about to call createBasicCAExtensions()"); + exts = createBasicCAExtensions(config); + } + PKCS10 certReq = CryptoUtil.createCertificationRequest(caDN, pubk, privk, algorithm, exts); CMS.debug("handleCertRequest: created cert request"); byte[] certReqb = certReq.toByteArray(); @@ -2727,6 +2741,68 @@ public class ConfigurationUtils { } + /* + * createBasicCAExtensions creates the basic Extensions needed for a CSR to a + * CA signing certificate + */ + private static Extensions createBasicCAExtensions(IConfigStore config) throws IOException { + Extensions exts = new Extensions(); + CMS.debug("ConfigurationUtils: createBasicCAExtensions: begins"); + + // create BasicConstraintsExtension + BasicConstraintsExtension bcExt = new BasicConstraintsExtension(true, -1); + exts.add(bcExt); + + // create KeyUsageExtension + boolean[] kuBits = new boolean[KeyUsageExtension.NBITS]; + for (int i = 0; i < kuBits.length; i++) { + kuBits[i] = false; + } + kuBits[KeyUsageExtension.DIGITAL_SIGNATURE_BIT] = true; + kuBits[KeyUsageExtension.NON_REPUDIATION_BIT] = true; + kuBits[KeyUsageExtension.KEY_CERTSIGN_BIT] = true; + kuBits[KeyUsageExtension.CRL_SIGN_BIT] = true; + KeyUsageExtension kuExt = new KeyUsageExtension(true, kuBits); + exts.add(kuExt); + + /* save this for later when we want to allow more selection for pkispawn configuration + // create NSCertTypeExtension + boolean[] nsBits = new boolean[NSCertTypeExtension.NBITS]; + for (int i = 0; i < nsBits.length; i++) { + nsBits[i] = false; + } + nsBits[NSCertTypeExtension.SSL_CA_BIT] = true; + NSCertTypeExtension nsctExt = new NSCertTypeExtension(false, nsBits); + exts.add(nsctExt); + */ + + // add a generic extension + Extension genExt = null; + try { + String oidString = config.getString(PCERT_PREFIX + "signing.ext.oid"); + String dataString = config.getString(PCERT_PREFIX + "signing.ext.data"); + boolean critical = false; + if (oidString != null && dataString != null) { + CMS.debug("ConfigurationUtils: createBasicCAExtensions: processing generic extension"); + critical = config.getBoolean("preop.cert.signing.ext.critical"); + ObjectIdentifier oid = new ObjectIdentifier(oidString); + + byte data[] = CryptoUtil.hexString2Bytes(dataString); + DerOutputStream out = new DerOutputStream(); + out.putOctetString(data); + genExt = new Extension(oid, critical, out.toByteArray()); + out.close(); + + exts.add(genExt); + CMS.debug("ConfigurationUtils: createBasicCAExtensions: generic extension added: " + oidString); + } + } catch (EBaseException e) { + CMS.debug("ConfigurationUtils: createBasicCAExtensions: generic extension not processed:" + e); + } + + return exts; + } + public static X509Key getECCX509Key(IConfigStore config, String certTag) throws EPropertyNotFound, EBaseException, InvalidKeyException { X509Key pubk = null; diff --git a/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java b/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java index 96a6cf0bf..fa762774a 100644 --- a/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java +++ b/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java @@ -309,6 +309,14 @@ public class SystemConfigService extends PKIService implements SystemConfigResou if (systemCert.getTag().equals(tag)) { certData = systemCert; CMS.debug("Found data for '" + tag + "'"); + if (tag.equals("signing") && + certData.getReqExtOID() != null && + certData.getReqExtData() != null) { + CMS.debug("SystemConfigService:processCerts: adding request extension to config"); + cs.putString("preop.cert.signing.ext.oid", certData.getReqExtOID()); + cs.putString("preop.cert.signing.ext.data", certData.getReqExtData()); + cs.putBoolean("preop.cert.signing.ext.critical", certData.getReqExtCritical()); + } break; } } @@ -382,6 +390,7 @@ public class SystemConfigService extends PKIService implements SystemConfigResou cs.putString("preop.cert." + tag + ".signingalgorithm", signingalgorithm); cs.putString("preop.cert." + tag + ".nickname", nickname); cs.putString("preop.cert." + tag + ".dn", dn); + cs.commit(false); if (!request.getStepTwo()) { if (keytype.equals("ecc")) { diff --git a/base/server/etc/default.cfg b/base/server/etc/default.cfg index 9047e6e7c..686cc59f9 100644 --- a/base/server/etc/default.cfg +++ b/base/server/etc/default.cfg @@ -347,6 +347,11 @@ pki_ca_signing_signing_algorithm=SHA256withRSA pki_ca_signing_subject_dn=cn=CA Signing Certificate,o=%(pki_security_domain_name)s pki_ca_signing_token=Internal Key Storage Token pki_external=False +pki_req_ext_add=False +# MS subca request ext data +pki_req_ext_oid=1.3.6.1.4.1.311.20.2 +pki_req_ext_critical=False +pki_req_ext_data=1E0A00530075006200430041 pki_external_csr_path=%(pki_instance_configuration_path)s/ca_signing.csr pki_external_step_two=False pki_external_ca_cert_chain_path=%(pki_instance_configuration_path)s/external_ca_chain.cert diff --git a/base/server/python/pki/server/deployment/pkihelper.py b/base/server/python/pki/server/deployment/pkihelper.py index a35b8f347..b4c728a87 100644 --- a/base/server/python/pki/server/deployment/pkihelper.py +++ b/base/server/python/pki/server/deployment/pkihelper.py @@ -447,7 +447,16 @@ class ConfigurationFile: self.mdict = deployer.mdict # set useful 'boolean' object variables for this class self.clone = config.str2bool(self.mdict['pki_clone']) + # generic extension support in CSR - for external CA + self.add_req_ext = config.str2bool( + self.mdict['pki_req_ext_add']) self.external = config.str2bool(self.mdict['pki_external']) + if self.external: + # generic extension support in CSR - for external CA + if self.add_req_ext: + self.req_ext_oid = self.mdict['pki_req_ext_oid'] + self.req_ext_critical = self.mdict['pki_req_ext_critical'] + self.req_ext_data = self.mdict['pki_req_ext_data'] self.external_step_two = config.str2bool( self.mdict['pki_external_step_two']) self.skip_configuration = config.str2bool( @@ -660,6 +669,11 @@ class ConfigurationFile: # External CA (Step 1) self.confirm_data_exists("pki_external_csr_path") self.confirm_missing_file("pki_external_csr_path") + # generic extension support in CSR - for external CA + if self.add_req_ext: + self.confirm_data_exists("pki_req_ext_oid") + self.confirm_data_exists("pki_req_ext_critical") + self.confirm_data_exists("pki_req_ext_data") else: # External CA (Step 2) self.confirm_data_exists("pki_external_ca_cert_chain_path") @@ -3397,6 +3411,9 @@ class ConfigClient: self.subordinate = config.str2bool(self.mdict['pki_subordinate']) # set useful 'string' object variables for this class self.subsystem = self.mdict['pki_subsystem'] + # generic extension support in CSR - for external CA + self.add_req_ext = config.str2bool( + self.mdict['pki_req_ext_add']) def configure_pki_data(self, data): config.pki_log.info( @@ -3715,6 +3732,14 @@ class ConfigClient: cert1 = self.create_system_cert("ca_signing") cert1.signingAlgorithm = \ self.mdict['pki_ca_signing_signing_algorithm'] + # generic extension support in CSR - for external CA + if self.add_req_ext: + cert1.req_ext_oid = \ + self.mdict['pki_req_ext_oid'] + cert1.req_ext_critical = \ + self.mdict['pki_req_ext_critical'] + cert1.req_ext_data = \ + self.mdict['pki_req_ext_data'] if self.external_step_two: # External CA (Step 2) or Stand-alone PKI (Step 2) if not self.subsystem == "CA": diff --git a/base/server/python/pki/server/deployment/pkiparser.py b/base/server/python/pki/server/deployment/pkiparser.py index 049ebf518..de224eb9a 100644 --- a/base/server/python/pki/server/deployment/pkiparser.py +++ b/base/server/python/pki/server/deployment/pkiparser.py @@ -569,6 +569,9 @@ class PKIConfigParser: if not 'pki_external' in self.mdict or\ not len(self.mdict['pki_external']): self.mdict['pki_external'] = "false" + if not 'pki_req_ext_add' in self.mdict or\ + not len(self.mdict['pki_req_ext_add']): + self.mdict['pki_req_ext_add'] = "false" if not 'pki_external_step_two' in self.mdict or\ not len(self.mdict['pki_external_step_two']): self.mdict['pki_external_step_two'] = "false" diff --git a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java index ee077872f..cf2bafac1 100644 --- a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java +++ b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java @@ -46,7 +46,10 @@ import java.util.Vector; import javax.crypto.SecretKey; import netscape.security.pkcs.PKCS10; +import netscape.security.pkcs.PKCS10Attribute; +import netscape.security.pkcs.PKCS10Attributes; import netscape.security.pkcs.PKCS7; +import netscape.security.pkcs.PKCS9Attribute; import netscape.security.util.BigInt; import netscape.security.util.DerInputStream; import netscape.security.util.DerOutputStream; @@ -62,6 +65,7 @@ import netscape.security.x509.CertificateSubjectName; import netscape.security.x509.CertificateValidity; import netscape.security.x509.CertificateVersion; import netscape.security.x509.CertificateX509Key; +import netscape.security.x509.Extensions; import netscape.security.x509.X500Name; import netscape.security.x509.X500Signer; import netscape.security.x509.X509CertImpl; @@ -1179,12 +1183,36 @@ public class CryptoUtil { throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, IOException, CertificateException, SignatureException { + return createCertificationRequest(subjectName, pubk, prik, alg, null); + } + + /* + * This createCertificationRequest() allows extensions to be added to the CSR + */ + public static PKCS10 createCertificationRequest(String subjectName, + X509Key pubk, PrivateKey prik, String alg, Extensions exts) + throws NoSuchAlgorithmException, NoSuchProviderException, + InvalidKeyException, IOException, CertificateException, + SignatureException { X509Key key = pubk; java.security.Signature sig = java.security.Signature.getInstance(alg, "Mozilla-JSS"); sig.initSign(prik); - PKCS10 pkcs10 = new PKCS10(key); + PKCS10 pkcs10 = null; + + if (exts != null) { + PKCS10Attribute attr = new + PKCS10Attribute(PKCS9Attribute.EXTENSION_REQUEST_OID, + exts); + PKCS10Attributes attrs = new PKCS10Attributes(); + + attrs.setAttribute(attr.getAttributeValue().getName(), attr); + + pkcs10 = new PKCS10(key, attrs); + } else { + pkcs10 = new PKCS10(key); + } X500Name name = new X500Name(subjectName); X500Signer signer = new X500Signer(sig, name); @@ -1350,6 +1378,25 @@ public class CryptoUtil { } /** + * Converts string containing pairs of characters in the range of '0' + * to '9', 'a' to 'f' to an array of bytes such that each pair of + * characters in the string represents an individual byte + */ + public static byte[] hexString2Bytes(String string) { + if (string == null) + return null; + int stringLength = string.length(); + if ((stringLength == 0) || ((stringLength % 2) != 0)) + return null; + byte[] bytes = new byte[(stringLength / 2)]; + for (int i = 0, b = 0; i < stringLength; i += 2, ++b) { + String nextByte = string.substring(i, (i + 2)); + bytes[b] = (byte) Integer.parseInt(nextByte, 0x10); + } + return bytes; + } + + /** * Retrieves a private key from a unique key ID. */ public static PrivateKey findPrivateKeyFromID(byte id[]) |