Blame SOURCES/pki-core-add-profile-component-that-copies-CN-to-SAN.patch

55b77f
From fa65ec19458bbd767f54e52f61d920b529936e19 Mon Sep 17 00:00:00 2001
55b77f
From: Fraser Tweedale <ftweedal@redhat.com>
55b77f
Date: Wed, 1 Feb 2017 16:15:39 +1000
55b77f
Subject: [PATCH 1/5] DNSName: add method to get value
55b77f
55b77f
To implement a profile default that copies CN to SAN dNSName, we
55b77f
need to examine existing dNSName values.  To support this, add the
55b77f
'getValue()' method to 'DNSName'.
55b77f
55b77f
Part of: https://fedorahosted.org/pki/ticket/1710
55b77f
55b77f
(cherry picked from commit f371114134ee3b6a83b747eecf46e001080b1e9c)
55b77f
(cherry picked from commit a30f25cbb496b6e24b417a02602e0cdbe079cbd3)
55b77f
---
55b77f
 base/util/src/netscape/security/x509/DNSName.java | 8 ++++++++
55b77f
 1 file changed, 8 insertions(+)
55b77f
55b77f
diff --git a/base/util/src/netscape/security/x509/DNSName.java b/base/util/src/netscape/security/x509/DNSName.java
55b77f
index 361c235..2161adf 100644
55b77f
--- a/base/util/src/netscape/security/x509/DNSName.java
55b77f
+++ b/base/util/src/netscape/security/x509/DNSName.java
55b77f
@@ -79,4 +79,12 @@ public class DNSName implements GeneralNameInterface {
55b77f
     public String toString() {
55b77f
         return ("DNSName: " + name);
55b77f
     }
55b77f
+
55b77f
+    /**
55b77f
+     * Get the raw DNSName value.
55b77f
+     */
55b77f
+    public String getValue() {
55b77f
+        return name;
55b77f
+    }
55b77f
+
55b77f
 }
55b77f
-- 
55b77f
1.8.3.1
55b77f
55b77f
55b77f
From 6fa86d4f50b5846f5d6f8a12797f61dd5b629cca Mon Sep 17 00:00:00 2001
55b77f
From: Fraser Tweedale <ftweedal@redhat.com>
55b77f
Date: Wed, 1 Feb 2017 16:17:51 +1000
55b77f
Subject: [PATCH 2/5] GeneralName: add method to get at inner value
55b77f
55b77f
The 'GeneralNameInterface' interface represents a single X.509
55b77f
General Name value.  Various types are supported.  The 'GeneralName'
55b77f
class (which also implements 'GeneralNameInterface') is a singleton
55b77f
container for another 'GeneralNameInterface' value.
55b77f
55b77f
To implement a profile component that copies CN to a SAN dNSName, we
55b77f
need to examine existing General Names in the SAN extension (if
55b77f
present), to avoid duplicate values.  We can iterate 'GeneralNames',
55b77f
but if the value is of type 'GeneralName' we need a way to "unwrap"
55b77f
the value, down to the innermost value which will be of a specific
55b77f
General Name type.
55b77f
55b77f
Add the 'unwrap' method to 'GeneralName'.
55b77f
55b77f
Part of: https://fedorahosted.org/pki/ticket/1710
55b77f
55b77f
(cherry picked from commit 225dd099efa7e2f752c3f50157aaec71a9834873)
55b77f
(cherry picked from commit 52704d6564800c6872d3343c9aa5d6180637f070)
55b77f
---
55b77f
 base/util/src/netscape/security/x509/GeneralName.java | 15 +++++++++++++++
55b77f
 1 file changed, 15 insertions(+)
55b77f
55b77f
diff --git a/base/util/src/netscape/security/x509/GeneralName.java b/base/util/src/netscape/security/x509/GeneralName.java
55b77f
index a90ac7b..55b5bfc 100644
55b77f
--- a/base/util/src/netscape/security/x509/GeneralName.java
55b77f
+++ b/base/util/src/netscape/security/x509/GeneralName.java
55b77f
@@ -196,4 +196,19 @@ public class GeneralName implements GeneralNameInterface {
55b77f
                              constructedForm, (byte) nameType), tmp);
55b77f
         }
55b77f
     }
55b77f
+
55b77f
+    /**
55b77f
+     * Unwrap this GeneralName until we reach something that is not
55b77f
+     * a GeneralName.
55b77f
+     */
55b77f
+    public GeneralNameInterface unwrap() {
55b77f
+        if (this == name)
55b77f
+            return null;  // can't happen, but just in case...
55b77f
+
55b77f
+        if (name instanceof GeneralName)
55b77f
+            return ((GeneralName) name).unwrap();
55b77f
+        else
55b77f
+            return name;
55b77f
+    }
55b77f
+
55b77f
 }
55b77f
-- 
55b77f
1.8.3.1
55b77f
55b77f
55b77f
From 6eac5bbccb18fe913c43a0b9ec73707180870bb9 Mon Sep 17 00:00:00 2001
55b77f
From: Fraser Tweedale <ftweedal@redhat.com>
55b77f
Date: Wed, 1 Feb 2017 16:25:11 +1000
55b77f
Subject: [PATCH 3/5] SubjectAlternativeNameExtension: add GeneralNames
55b77f
 getter/setter
55b77f
55b77f
To implement a profile default that copies CN to SAN dNSName, we
55b77f
need to read and set the 'GeneralNames' of the extension.  This can
55b77f
be done via the 'get' and 'set' methods but this interface is
55b77f
awkward and requires the caller to deal with exceptions that aren't
55b77f
fundamental to the get/set actions.
55b77f
55b77f
Add the 'setGeneralNames' and 'getGeneralNames' methods.
55b77f
55b77f
Part of: https://fedorahosted.org/pki/ticket/1710
55b77f
55b77f
(cherry picked from commit a67816eebbed2332327fbf391f3e23223ee7690e)
55b77f
(cherry picked from commit 60f4011c3f4511ac8f86b77940d25b5869204353)
55b77f
---
55b77f
 .../security/x509/SubjectAlternativeNameExtension.java    | 15 +++++++++++++++
55b77f
 1 file changed, 15 insertions(+)
55b77f
55b77f
diff --git a/base/util/src/netscape/security/x509/SubjectAlternativeNameExtension.java b/base/util/src/netscape/security/x509/SubjectAlternativeNameExtension.java
55b77f
index d96c821..82f87e1 100644
55b77f
--- a/base/util/src/netscape/security/x509/SubjectAlternativeNameExtension.java
55b77f
+++ b/base/util/src/netscape/security/x509/SubjectAlternativeNameExtension.java
55b77f
@@ -199,6 +199,21 @@ public class SubjectAlternativeNameExtension extends Extension
55b77f
     }
55b77f
 
55b77f
     /**
55b77f
+     * Set the GeneralNames of this extension.
55b77f
+     */
55b77f
+    public void setGeneralNames(GeneralNames names) {
55b77f
+        clearValue();
55b77f
+        this.names = names;
55b77f
+    }
55b77f
+
55b77f
+    /**
55b77f
+     * Get the GeneralNames of this extension.
55b77f
+     */
55b77f
+    public GeneralNames getGeneralNames() {
55b77f
+        return names;
55b77f
+    }
55b77f
+
55b77f
+    /**
55b77f
      * Get the attribute value.
55b77f
      */
55b77f
     public Object get(String name) throws IOException {
55b77f
-- 
55b77f
1.8.3.1
55b77f
55b77f
55b77f
From da8cab2d15d5bd5e82ad8bd9a2ff0f51f7bad343 Mon Sep 17 00:00:00 2001
55b77f
From: Fraser Tweedale <ftweedal@redhat.com>
55b77f
Date: Wed, 1 Feb 2017 16:30:50 +1000
55b77f
Subject: [PATCH 4/5] X500Name: add method to get all attributes of a given
55b77f
 type
55b77f
55b77f
To implement a profile default that copies the CN to a SAN dNSName,
55b77f
we need to examine the CN values present in the Subject DN.
55b77f
Specifically, we want to look at the "most specific" CN value.  The
55b77f
'getCommonName' method returns the "least specific" value in the
55b77f
name, thus is not suitable.
55b77f
55b77f
Add the 'getAttributesForOid(ObjectIdentifier)' method, which
55b77f
returns an ordered list of values of the given name attribute type,
55b77f
from least specific to most specific.
55b77f
55b77f
Part of: https://fedorahosted.org/pki/ticket/1710
55b77f
55b77f
(cherry picked from commit 979b6a2da433e97c1ada6434b432aa4aabc47ab5)
55b77f
(cherry picked from commit 4ba23db518ab285d8a0dce8d4ee493f695867ad8)
55b77f
---
55b77f
 base/util/src/netscape/security/x509/X500Name.java | 21 +++++++++++++++++++++
55b77f
 1 file changed, 21 insertions(+)
55b77f
55b77f
diff --git a/base/util/src/netscape/security/x509/X500Name.java b/base/util/src/netscape/security/x509/X500Name.java
55b77f
index 0f75f48..c8627a9 100644
55b77f
--- a/base/util/src/netscape/security/x509/X500Name.java
55b77f
+++ b/base/util/src/netscape/security/x509/X500Name.java
55b77f
@@ -19,8 +19,10 @@ package netscape.security.x509;
55b77f
 
55b77f
 import java.io.IOException;
55b77f
 import java.security.Principal;
55b77f
+import java.util.ArrayList;
55b77f
 import java.util.Arrays;
55b77f
 import java.util.Enumeration;
55b77f
+import java.util.List;
55b77f
 import java.util.Vector;
55b77f
 
55b77f
 import netscape.security.util.DerInputStream;
55b77f
@@ -451,6 +453,25 @@ public class X500Name implements Principal, GeneralNameInterface {
55b77f
     }
55b77f
 
55b77f
     /**
55b77f
+     * Return a list of attributes of the given type.
55b77f
+     *
55b77f
+     * The "most specific" value comes last.
55b77f
+     *
55b77f
+     * If there are no name attributes of the given type, an empty
55b77f
+     * list is returned.
55b77f
+     */
55b77f
+    public List<String> getAttributesForOid(ObjectIdentifier oid)
55b77f
+            throws IOException {
55b77f
+        List<String> xs = new ArrayList<>();
55b77f
+        for (int i = 0; i < names.length; i++) {
55b77f
+            DerValue v = names[i].findAttribute(oid);
55b77f
+            if (v != null)
55b77f
+                xs.add(getString(v));
55b77f
+        }
55b77f
+        return xs;
55b77f
+    }
55b77f
+
55b77f
+    /**
55b77f
      * Returns a Ldap DN String from the X500Name
55b77f
      * using the specified LdapDNStrconverter.
55b77f
      * For example, RFC1779String converter can be passed to convert the
55b77f
-- 
55b77f
1.8.3.1
55b77f
55b77f
55b77f
From 10799f1af01143ffb27fae06f446bb389c0787e8 Mon Sep 17 00:00:00 2001
55b77f
From: Fraser Tweedale <ftweedal@redhat.com>
55b77f
Date: Wed, 1 Feb 2017 16:39:14 +1000
55b77f
Subject: [PATCH 5/5] Add profile component that copies CN to SAN dNSName
55b77f
55b77f
Add the 'CommonNameToSANDefault' profile default class.  When used
55b77f
on a profile, this will examine the (most-specific) Common Name in
55b77f
the Subject DN, and if it looks like a DNS name, will add it to the
55b77f
Subject Alternative Name extension, creating the extension if it
55b77f
does not already exist.
55b77f
55b77f
Also add upgrade scriptlet to add the component to registry.cfg in
55b77f
existing installations.
55b77f
55b77f
Fixes: https://fedorahosted.org/pki/ticket/1710
55b77f
(cherry picked from commit 9cb00049ec731cca36de822f6c1e834f7febcb4f)
55b77f
(cherry picked from commit 10d1db00225caf750ccc3c50b9d6e6b7af3655a8)
55b77f
---
55b77f
 base/ca/shared/conf/registry.cfg                   |   5 +-
55b77f
 .../cms/profile/def/CommonNameToSANDefault.java    | 215 +++++++++++++++++++++
55b77f
 2 files changed, 219 insertions(+), 1 deletion(-)
55b77f
 create mode 100644 base/server/cms/src/com/netscape/cms/profile/def/CommonNameToSANDefault.java
55b77f
55b77f
diff --git a/base/ca/shared/conf/registry.cfg b/base/ca/shared/conf/registry.cfg
55b77f
index 0bd7c05..280c713 100644
55b77f
--- a/base/ca/shared/conf/registry.cfg
55b77f
+++ b/base/ca/shared/conf/registry.cfg
55b77f
@@ -45,7 +45,7 @@ constraintPolicy.renewGracePeriodConstraintImpl.name=Renewal Grace Period Constr
55b77f
 constraintPolicy.uniqueKeyConstraintImpl.class=com.netscape.cms.profile.constraint.UniqueKeyConstraint
55b77f
 constraintPolicy.uniqueKeyConstraintImpl.desc=Unique Public Key Constraint
55b77f
 constraintPolicy.uniqueKeyConstraintImpl.name=Unique Public Key Constraint
55b77f
-defaultPolicy.ids=noDefaultImpl,genericExtDefaultImpl,autoAssignDefaultImpl,subjectNameDefaultImpl,validityDefaultImpl,randomizedValidityDefaultImpl,caValidityDefaultImpl,subjectKeyIdentifierExtDefaultImpl,authorityKeyIdentifierExtDefaultImpl,basicConstraintsExtDefaultImpl,keyUsageExtDefaultImpl,nsCertTypeExtDefaultImpl,extendedKeyUsageExtDefaultImpl,ocspNoCheckExtDefaultImpl,issuerAltNameExtDefaultImpl,subjectAltNameExtDefaultImpl,userSubjectNameDefaultImpl,signingAlgDefaultImpl,userKeyDefaultImpl,userValidityDefaultImpl,userExtensionDefaultImpl,userSigningAlgDefaultImpl,authTokenSubjectNameDefaultImpl,subjectInfoAccessExtDefaultImpl,authInfoAccessExtDefaultImpl,nscCommentExtDefaultImpl,freshestCRLExtDefaultImpl,crlDistributionPointsExtDefaultImpl,policyConstraintsExtDefaultImpl,policyMappingsExtDefaultImpl,nameConstraintsExtDefaultImpl,certificateVersionDefaultImpl,certificatePoliciesExtDefaultImpl,subjectDirAttributesExtDefaultImpl,privateKeyPeriodExtDefaultImpl,inhibitAnyPolicyExtDefaultImpl,imageDefaultImpl,nsTokenDeviceKeySubjectNameDefaultImpl,nsTokenUserKeySubjectNameDefaultImpl,authzRealmDefaultImpl
55b77f
+defaultPolicy.ids=noDefaultImpl,genericExtDefaultImpl,autoAssignDefaultImpl,subjectNameDefaultImpl,validityDefaultImpl,randomizedValidityDefaultImpl,caValidityDefaultImpl,subjectKeyIdentifierExtDefaultImpl,authorityKeyIdentifierExtDefaultImpl,basicConstraintsExtDefaultImpl,keyUsageExtDefaultImpl,nsCertTypeExtDefaultImpl,extendedKeyUsageExtDefaultImpl,ocspNoCheckExtDefaultImpl,issuerAltNameExtDefaultImpl,subjectAltNameExtDefaultImpl,userSubjectNameDefaultImpl,signingAlgDefaultImpl,userKeyDefaultImpl,userValidityDefaultImpl,userExtensionDefaultImpl,userSigningAlgDefaultImpl,authTokenSubjectNameDefaultImpl,subjectInfoAccessExtDefaultImpl,authInfoAccessExtDefaultImpl,nscCommentExtDefaultImpl,freshestCRLExtDefaultImpl,crlDistributionPointsExtDefaultImpl,policyConstraintsExtDefaultImpl,policyMappingsExtDefaultImpl,nameConstraintsExtDefaultImpl,certificateVersionDefaultImpl,certificatePoliciesExtDefaultImpl,subjectDirAttributesExtDefaultImpl,privateKeyPeriodExtDefaultImpl,inhibitAnyPolicyExtDefaultImpl,imageDefaultImpl,nsTokenDeviceKeySubjectNameDefaultImpl,nsTokenUserKeySubjectNameDefaultImpl,authzRealmDefaultImpl,commonNameToSANDefaultImpl
55b77f
 defaultPolicy.autoAssignDefaultImpl.class=com.netscape.cms.profile.def.AutoAssignDefault
55b77f
 defaultPolicy.autoAssignDefaultImpl.desc=Auto Request Assignment Default
55b77f
 defaultPolicy.autoAssignDefaultImpl.name=Auto Request Assignment Default
55b77f
@@ -166,6 +166,9 @@ defaultPolicy.subjectDirAttributesExtDefaultImpl.name=Subject Directory Attribut
55b77f
 defaultPolicy.inhibitAnyPolicyExtDefaultImpl.class=com.netscape.cms.profile.def.InhibitAnyPolicyExtDefault
55b77f
 defaultPolicy.inhibitAnyPolicyExtDefaultImpl.desc=Inhibit Any-Policy Extension Default
55b77f
 defaultPolicy.inhibitAnyPolicyExtDefaultImpl.name=Inhibit Any-Policy Extension Default
55b77f
+defaultPolicy.commonNameToSANDefaultImpl.class=com.netscape.cms.profile.def.CommonNameToSANDefault
55b77f
+defaultPolicy.commonNameToSANDefaultImpl.desc=Copy Common Name to Subject Alternative Name
55b77f
+defaultPolicy.commonNameToSANDefaultImpl.name=Copy Common Name to Subject Alternative Name
55b77f
 profile.ids=caEnrollImpl,caCACertEnrollImpl,caServerCertEnrollImpl,caUserCertEnrollImpl
55b77f
 profile.caEnrollImpl.class=com.netscape.cms.profile.common.CAEnrollProfile
55b77f
 profile.caEnrollImpl.desc=Certificate Authority Generic Certificate Enrollment Profile
55b77f
diff --git a/base/server/cms/src/com/netscape/cms/profile/def/CommonNameToSANDefault.java b/base/server/cms/src/com/netscape/cms/profile/def/CommonNameToSANDefault.java
55b77f
new file mode 100644
55b77f
index 0000000..33828d1
55b77f
--- /dev/null
55b77f
+++ b/base/server/cms/src/com/netscape/cms/profile/def/CommonNameToSANDefault.java
55b77f
@@ -0,0 +1,215 @@
55b77f
+// --- BEGIN COPYRIGHT BLOCK ---
55b77f
+// This program is free software; you can redistribute it and/or modify
55b77f
+// it under the terms of the GNU General Public License as published by
55b77f
+// the Free Software Foundation; version 2 of the License.
55b77f
+//
55b77f
+// This program is distributed in the hope that it will be useful,
55b77f
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
55b77f
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
55b77f
+// GNU General Public License for more details.
55b77f
+//
55b77f
+// You should have received a copy of the GNU General Public License along
55b77f
+// with this program; if not, write to the Free Software Foundation, Inc.,
55b77f
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
55b77f
+//
55b77f
+// (C) 2017 Red Hat, Inc.
55b77f
+// All rights reserved.
55b77f
+// --- END COPYRIGHT BLOCK ---
55b77f
+
55b77f
+package com.netscape.cms.profile.def;
55b77f
+
55b77f
+import java.io.IOException;
55b77f
+import java.security.cert.CertificateException;
55b77f
+import java.util.List;
55b77f
+import java.util.Locale;
55b77f
+
55b77f
+import netscape.security.x509.CertificateSubjectName;
55b77f
+import netscape.security.x509.DNSName;
55b77f
+import netscape.security.x509.GeneralName;
55b77f
+import netscape.security.x509.GeneralNameInterface;
55b77f
+import netscape.security.x509.GeneralNames;
55b77f
+import netscape.security.x509.PKIXExtensions;
55b77f
+import netscape.security.x509.SubjectAlternativeNameExtension;
55b77f
+import netscape.security.x509.X500Name;
55b77f
+import netscape.security.x509.X509CertInfo;
55b77f
+
55b77f
+import com.netscape.certsrv.apps.CMS;
55b77f
+import com.netscape.certsrv.profile.EProfileException;
55b77f
+import com.netscape.certsrv.property.IDescriptor;
55b77f
+import com.netscape.certsrv.request.IRequest;
55b77f
+
55b77f
+/**
55b77f
+ * This plugin will examine the most specific CN in the Subject DN,
55b77f
+ * and if it looks like a DNS name, will add it to the SAN extension.
55b77f
+ *
55b77f
+ * It will create the SAN extension if necessary.
55b77f
+ *
55b77f
+ * If there is already a SAN dnsName value that matches
55b77f
+ * (case-insensitively) the CN, it will not add the name.
55b77f
+ *
55b77f
+ * If there is no CN in the subject DN, does nothing.
55b77f
+ *
55b77f
+ * If the most specific CN does not look like a DNS name, does
55b77f
+ * nothing.
55b77f
+ *
55b77f
+ * This profile component should be configured to execute after
55b77f
+ * other profile components that set or modify the Subject DN or the
55b77f
+ * SAN extension.
55b77f
+ */
55b77f
+public class CommonNameToSANDefault extends EnrollExtDefault {
55b77f
+
55b77f
+    private static final String LOG_PREFIX = "CommonNameToSANDefault: ";
55b77f
+
55b77f
+    public void populate(IRequest _req, X509CertInfo info)
55b77f
+            throws EProfileException {
55b77f
+        // examine the Subject DN
55b77f
+        CertificateSubjectName subjectName;
55b77f
+        try {
55b77f
+            subjectName = (CertificateSubjectName) info.get(X509CertInfo.SUBJECT);
55b77f
+        } catch (CertificateException | IOException e) {
55b77f
+            CMS.debug(LOG_PREFIX + "failed to read Subject DN: " + e);
55b77f
+            return;
55b77f
+        }
55b77f
+        X500Name sdn;
55b77f
+        try {
55b77f
+            sdn = (X500Name) subjectName.get(CertificateSubjectName.DN_NAME);
55b77f
+        } catch (IOException e) {
55b77f
+            CMS.debug(LOG_PREFIX + "failed to retrieve SDN X500Name: " + e);
55b77f
+            return;
55b77f
+        }
55b77f
+        List<String> cns;
55b77f
+        try {
55b77f
+            cns = sdn.getAttributesForOid(X500Name.commonName_oid);
55b77f
+        } catch (IOException e) {
55b77f
+            // Couldn't read the CN for some reason.
55b77f
+            // Not a likely scenario so just log and return.
55b77f
+            CMS.debug(LOG_PREFIX + "failed to decode CN: " + e);
55b77f
+            return;
55b77f
+        }
55b77f
+        if (cns.size() < 1) {
55b77f
+            CMS.debug(LOG_PREFIX + "No CN in Subject DN; done");
55b77f
+            return;  // no Common Name; can't do anything
55b77f
+        }
55b77f
+
55b77f
+        String cn = cns.get(cns.size() - 1); // "most specific" CN is at end
55b77f
+
55b77f
+        CMS.debug(LOG_PREFIX + "Examining CN: " + cn);
55b77f
+
55b77f
+        if (!isValidDNSName(cn)) {
55b77f
+            CMS.debug(LOG_PREFIX + "CN is not a DNS name; done");
55b77f
+            return;  // CN does not look like a DNS name
55b77f
+        }
55b77f
+
55b77f
+        SubjectAlternativeNameExtension san = (SubjectAlternativeNameExtension)
55b77f
+            getExtension(PKIXExtensions.SubjectAlternativeName_Id.toString(), info);
55b77f
+
55b77f
+        if (san != null) {
55b77f
+            // check for existing name matching CN
55b77f
+            GeneralNames gns = san.getGeneralNames();
55b77f
+            for (GeneralNameInterface gn : gns) {
55b77f
+                if (gn instanceof GeneralName)
55b77f
+                    gn = ((GeneralName) gn).unwrap();
55b77f
+                if (gn instanceof DNSName) {
55b77f
+                    String dnsName = ((DNSName) gn).getValue();
55b77f
+                    if (cn.equalsIgnoreCase(dnsName)) {
55b77f
+                        CMS.debug(LOG_PREFIX
55b77f
+                            + "CN already has corresponding SAN dNSName; done");
55b77f
+                        return;  // CN is already in SAN
55b77f
+                    }
55b77f
+                }
55b77f
+            }
55b77f
+            gns.add(new DNSName(cn));  // add CN to SAN
55b77f
+
55b77f
+            // reset extension value (encoded value may have been cached)
55b77f
+            san.setGeneralNames(gns);
55b77f
+            CMS.debug(LOG_PREFIX + "added CN to SAN; done");
55b77f
+        } else {
55b77f
+            GeneralNames gns = new GeneralNames();
55b77f
+            gns.add(new DNSName(cn));
55b77f
+            try {
55b77f
+                san = new SubjectAlternativeNameExtension(gns);
55b77f
+                addExtension(
55b77f
+                    PKIXExtensions.SubjectAlternativeName_Id.toString(), san, info);
55b77f
+            } catch (IOException e) {
55b77f
+                CMS.debug(LOG_PREFIX + "failed to construct SAN ext: " + e);
55b77f
+                return;
55b77f
+            }
55b77f
+            CMS.debug(LOG_PREFIX + "added SAN extension containing CN; done");
55b77f
+        }
55b77f
+    }
55b77f
+
55b77f
+    public String getText(Locale locale) {
55b77f
+        return "This default add the Subject DN Common Name to the Subject "
55b77f
+            + "Alternative Name extension, if it looks like a DNS name.";
55b77f
+    }
55b77f
+
55b77f
+    public IDescriptor getValueDescriptor(Locale locale, String name) {
55b77f
+        return null;
55b77f
+    }
55b77f
+
55b77f
+    public String getValue(String name, Locale locale, X509CertInfo info) {
55b77f
+        return null;
55b77f
+    }
55b77f
+
55b77f
+    public void setValue(
55b77f
+            String name, Locale locale, X509CertInfo info, String value) {
55b77f
+    }
55b77f
+
55b77f
+    /** Validate DNS name syntax per Section 3.5 of RFC 1034
55b77f
+     * and Section 2.1 of RFC 1123, and the additional rules
55b77f
+     * of RFC 5280 Section 4.2.1.6.
55b77f
+     *
55b77f
+     * Further to those rules, we also ignore CNs that are valid
55b77f
+     * DNS names but which only have a single part (e.g. TLDs or
55b77f
+     * host short names).
55b77f
+     */
55b77f
+    public static boolean isValidDNSName(String s) {
55b77f
+        if (s == null)
55b77f
+            return false;
55b77f
+
55b77f
+        if (s.length() < 1 || s.length() > 255)
55b77f
+            return false;
55b77f
+
55b77f
+        String[] parts = s.split("\\.");
55b77f
+
55b77f
+        if (parts.length < 2)
55b77f
+            return false;
55b77f
+
55b77f
+        for (int i = 0; i < parts.length; i++) {
55b77f
+            char[] cs = parts[i].toCharArray();
55b77f
+
55b77f
+            if (cs.length < 1 || cs.length > 63)
55b77f
+                return false;
55b77f
+
55b77f
+            if (!isLetter(cs[0]))
55b77f
+                return false;
55b77f
+
55b77f
+            if (!isLetDig(cs[cs.length - 1]))
55b77f
+                return false;
55b77f
+
55b77f
+            for (int j = 0; j < cs.length; j++) {
55b77f
+                if (!isLetDigHyp(cs[j]))
55b77f
+                    return false;
55b77f
+            }
55b77f
+        }
55b77f
+
55b77f
+        return true;
55b77f
+    }
55b77f
+
55b77f
+    public static boolean isLetter(char c) {
55b77f
+        return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';
55b77f
+    }
55b77f
+
55b77f
+    public static boolean isDigit(char c) {
55b77f
+        return c >= '0' && c <= '9';
55b77f
+    }
55b77f
+
55b77f
+    public static boolean isLetDig(char c) {
55b77f
+        return isLetter(c) || isDigit(c);
55b77f
+    }
55b77f
+
55b77f
+    public static boolean isLetDigHyp(char c) {
55b77f
+        return isLetDig(c) || c == '-';
55b77f
+    }
55b77f
+
55b77f
+}
55b77f
-- 
55b77f
1.8.3.1
55b77f