Repository: dogtagpki/pki
Pull request #5090: Modify EST to send submitter information to CA
Author: login: fmarco76
Created: 2025-05-15T09:17:26Z | Merged: 2025-05-20T07:20:16Z

EST code is modified to send submitter information to the CA in order to apply policies constraints to the requested certificate.

The class `ClientAuthInfoInput` is created to allow input of user certificate and other information.


Diff:
diff --git a/base/ca/shared/conf/registry.cfg b/base/ca/shared/conf/registry.cfg
index fe13ad25334..f887464d560 100644
--- a/base/ca/shared/conf/registry.cfg
+++ b/base/ca/shared/conf/registry.cfg
@@ -209,7 +209,7 @@ profile.caServerCertEnrollImpl.name=Server Certificate Enrollment Profile
 profile.caUserCertEnrollImpl.class=com.netscape.cms.profile.common.UserCertCAEnrollProfile
 profile.caUserCertEnrollImpl.desc=Certificate Authority User Certificate Enrollment Profile
 profile.caUserCertEnrollImpl.name=User Certificate Enrollment Profile
-profileInput.ids=cmcCertReqInputImpl,certReqInputImpl,keyGenInputImpl,encKeyGenInputImpl,signKeyGenInputImpl,dualKeyGenInputImpl,subjectNameInputImpl,submitterInfoInputImpl,genericInputImpl,fileSigningInputImpl,imageInputImpl,subjectDNInputImpl,nsNKeyCertReqInputImpl,nsHKeyCertReqInputImpl,serialNumRenewInputImpl,subjectAltNameExtInputImpl,serverKeygenInputImpl
+profileInput.ids=cmcCertReqInputImpl,certReqInputImpl,keyGenInputImpl,encKeyGenInputImpl,signKeyGenInputImpl,dualKeyGenInputImpl,subjectNameInputImpl,submitterInfoInputImpl,raClientAuthInfoInputImpl,genericInputImpl,fileSigningInputImpl,imageInputImpl,subjectDNInputImpl,nsNKeyCertReqInputImpl,nsHKeyCertReqInputImpl,serialNumRenewInputImpl,subjectAltNameExtInputImpl,serverKeygenInputImpl
 profileInput.serverKeygenInputImpl.class=com.netscape.cms.profile.input.ServerKeygenInput
 profileInput.serverKeygenInputImpl.desc=Server-Side Keygen Input
 profileInput.serverKeygenInputImpl.name=Server-Side Keygen Input
@@ -228,6 +228,9 @@ profileInput.genericInputImpl.name=Generic Input
 profileInput.submitterInfoInputImpl.class=com.netscape.cms.profile.input.SubmitterInfoInput
 profileInput.submitterInfoInputImpl.desc=Submitter Information Input
 profileInput.submitterInfoInputImpl.name=Submitter Information Input
+profileInput.raClientAuthInfoInputImpl.class=com.netscape.cms.profile.input.RAClientAuthInfoInput
+profileInput.raClientAuthInfoInputImpl.desc=RA Client Authentication Information Input
+profileInput.raClientAuthInfoInputImpl.name=RA Client Authentication Information Input
 profileInput.certReqInputImpl.class=com.netscape.cms.profile.input.CertReqInput
 profileInput.certReqInputImpl.desc=Certificate Request Input
 profileInput.certReqInputImpl.name=Certificate Request Input
diff --git a/base/ca/shared/profiles/ca/estServiceCert.cfg b/base/ca/shared/profiles/ca/estServiceCert.cfg
index eff9032fcea..aaa9f79c978 100644
--- a/base/ca/shared/profiles/ca/estServiceCert.cfg
+++ b/base/ca/shared/profiles/ca/estServiceCert.cfg
@@ -6,7 +6,8 @@ desc=EST service certificate profile
 enable=true
 input.i1.class_id=certReqInputImpl
 input.i2.class_id=submitterInfoInputImpl
-input.list=i1,i2
+input.i3.class_id=raClientAuthInfoInputImpl
+input.list=i1,i2,i3
 name=EST Service Certificate Enrollment
 output.list=o1
 output.o1.class_id=certOutputImpl
diff --git a/base/ca/src/main/java/com/netscape/cms/profile/input/RAClientAuthInfoInput.java b/base/ca/src/main/java/com/netscape/cms/profile/input/RAClientAuthInfoInput.java
new file mode 100644
index 00000000000..43e867919f6
--- /dev/null
+++ b/base/ca/src/main/java/com/netscape/cms/profile/input/RAClientAuthInfoInput.java
@@ -0,0 +1,89 @@
+//
+// Copyright Red Hat, Inc.
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+package com.netscape.cms.profile.input;
+
+import java.util.Locale;
+import java.util.Map;
+
+import com.netscape.certsrv.profile.EProfileException;
+import com.netscape.certsrv.property.Descriptor;
+import com.netscape.certsrv.property.IDescriptor;
+import com.netscape.cms.profile.common.Profile;
+import com.netscape.cms.profile.common.ProfileInputConfig;
+import com.netscape.cmscore.apps.CMS;
+import com.netscape.cmscore.request.Request;
+
+/**
+ * This class implements the client authentication information
+ * input that collects RA client information such as uid, name,
+ * and certificate.
+ */
+public class RAClientAuthInfoInput extends EnrollInput {
+
+    public static final String UID = "ra_client_uid";
+    public static final String NAME = "ra_client_name";
+    public static final String CERT = "ra_client_certificate";
+
+    public RAClientAuthInfoInput() {
+        addValueName(UID);
+        addValueName(NAME);
+        addValueName(CERT);
+    }
+
+    /**
+     * Initializes this default policy.
+     */
+    @Override
+    public void init(Profile profile, ProfileInputConfig config) throws EProfileException {
+        super.init(profile, config);
+    }
+
+    /**
+     * Retrieves the localizable name of this policy.
+     */
+    @Override
+    public String getName(Locale locale) {
+        return CMS.getUserMessage(locale, "CMS_PROFILE_INPUT_RA_CLIENT_AUTH_NAME");
+    }
+
+    /**
+     * Retrieves the localizable description of this policy.
+     */
+    @Override
+    public String getText(Locale locale) {
+        return CMS.getUserMessage(locale, "CMS_PROFILE_INPUT_RA_CLIENT_AUTH_TEXT");
+    }
+
+    /**
+     * Populates the request with this policy default.
+     */
+    @Override
+    public void populate(Map<String, String> ctx, Request request) throws Exception {
+        //
+    }
+
+    /**
+     * Retrieves the descriptor of the given value
+     * parameter by name.
+     */
+    @Override
+    public IDescriptor getValueDescriptor(Locale locale, String name) {
+        if (name.equals(UID)) {
+            return new Descriptor(IDescriptor.STRING, null,
+                    null,
+                    CMS.getUserMessage(locale, "CMS_PROFILE_RA_CLIENT_UID"));
+        } else if (name.equals(NAME)) {
+            return new Descriptor(IDescriptor.STRING, null,
+                    null,
+                    CMS.getUserMessage(locale, "CMS_PROFILE_RA_CLIENT_NAME"));
+        } else if (name.equals(CERT)) {
+            return new Descriptor(IDescriptor.STRING, null,
+                    null,
+                    CMS.getUserMessage(locale, "CMS_PROFILE_RA_CLIENT_CERTIFICATE"));
+        }
+        return null;
+    }
+}
diff --git a/base/ca/src/main/java/com/netscape/cmscore/request/CertRequestRepository.java b/base/ca/src/main/java/com/netscape/cmscore/request/CertRequestRepository.java
index a197a22135a..c10427171f9 100644
--- a/base/ca/src/main/java/com/netscape/cmscore/request/CertRequestRepository.java
+++ b/base/ca/src/main/java/com/netscape/cmscore/request/CertRequestRepository.java
@@ -57,6 +57,9 @@ public Request createRequest(RequestId requestID, String requestType) throws EBa
         request.setExtData("requestor_name", "");
         request.setExtData("requestor_email", "");
         request.setExtData("requestor_phone", "");
+        request.setExtData("ra_client_uid", "");
+        request.setExtData("ra_client_name", "");
+        request.setExtData("ra_client_certificate", "");
         request.setExtData("profileRemoteHost", "");
         request.setExtData("profileRemoteAddr", "");
         request.setExtData("requestnotes", "");
diff --git a/base/est/src/main/java/org/dogtagpki/est/DogtagRABackend.java b/base/est/src/main/java/org/dogtagpki/est/DogtagRABackend.java
index 33b5bbdd634..fecd117f048 100644
--- a/base/est/src/main/java/org/dogtagpki/est/DogtagRABackend.java
+++ b/base/est/src/main/java/org/dogtagpki/est/DogtagRABackend.java
@@ -33,6 +33,7 @@
 import com.netscape.certsrv.profile.ProfileInput;
 import com.netscape.certsrv.request.RequestId;
 import com.netscape.certsrv.request.RequestStatus;
+import com.netscape.cms.realm.PKIPrincipal;
 
 /**
  * EST backend that acts as RA for a Dogtag CA subsystem
@@ -128,22 +129,22 @@ public CertificateChain cacerts(Optional<String> label) throws PKIException {
     }
 
     @Override
-    public X509CertImpl simpleenroll(Optional<String> label, PKCS10 csr, Object authzData)
+    public X509CertImpl simpleenroll(Optional<String> label, PKCS10 csr, ESTRequestAuthorizationData authzData, Object authzResult)
             throws PKIException {
-        return issueCertificate(label, csr);
+        return issueCertificate(label, csr, authzData);
     }
 
     @Override
-    public X509CertImpl simplereenroll(Optional<String> label, PKCS10 csr, Object authzData)
+    public X509CertImpl simplereenroll(Optional<String> label, PKCS10 csr, ESTRequestAuthorizationData authzData, Object authzResult)
             throws PKIException {
         /* At the moment, simplereenroll does the same thing as simpleenroll.
          * These are separate methods in case some backends need different or
          * additional behaviour for re-enroll (e.g. revoking previous certificates).
          */
-        return simpleenroll(label, csr, authzData);
+        return simpleenroll(label, csr, authzData, authzResult);
     }
 
-    private X509CertImpl issueCertificate(Optional<String> label, PKCS10 pkcs10)
+    private X509CertImpl issueCertificate(Optional<String> label, PKCS10 pkcs10, ESTRequestAuthorizationData authzData)
             throws PKIException {
         logger.info("Issuing certificate");
 
@@ -191,14 +192,32 @@ private X509CertImpl issueCertificate(Optional<String> label, PKCS10 pkcs10)
             CertEnrollmentRequest certEnrollmentRequest = certClient.getEnrollmentTemplate(profile);
 
             for (ProfileInput input : certEnrollmentRequest.getInputs()) {
-                ProfileAttribute typeAttr = input.getAttribute("cert_request_type");
-                if (typeAttr != null) {
-                    typeAttr.setValue("pkcs10");
-                }
-
-                ProfileAttribute csrAttr = input.getAttribute("cert_request");
-                if (csrAttr != null) {
-                    csrAttr.setValue(Utils.base64encodeSingleLine(pkcs10.toByteArray()));
+                logger.debug("Check input: {}", input.getClassId());
+                if (input.getClassId().equals("certReqInputImpl")) {
+                    ProfileAttribute typeAttr = input.getAttribute("cert_request_type");
+                    if (typeAttr != null) {
+                        typeAttr.setValue("pkcs10");
+                    }
+
+                    ProfileAttribute csrAttr = input.getAttribute("cert_request");
+                    if (csrAttr != null) {
+                        csrAttr.setValue(Utils.base64encodeSingleLine(pkcs10.toByteArray()));
+                    }
+                } else if (input.getClassId().equals("raClientAuthInfoInputImpl")) {
+                    ProfileAttribute uidAttr = input.getAttribute("ra_client_uid");
+                    if (uidAttr != null && authzData.principal != null) {
+                        uidAttr.setValue(authzData.principal.getName());
+                    }
+
+                    ProfileAttribute nameAttr = input.getAttribute("ra_client_name");
+                    if (nameAttr != null && authzData.principal instanceof PKIPrincipal pkiPrincipal) {
+                        nameAttr.setValue(pkiPrincipal.getUser().getFullName());
+                    }
+
+                    ProfileAttribute certAttr = input.getAttribute("ra_client_certificate");
+                    if (certAttr != null && authzData.clientCertChain != null) {
+                        certAttr.setValue(Utils.base64encodeSingleLine(authzData.clientCertChain[0].getEncoded()));
+                    }
                 }
             }
 
diff --git a/base/est/src/main/java/org/dogtagpki/est/ESTBackend.java b/base/est/src/main/java/org/dogtagpki/est/ESTBackend.java
index 88e8b08a8e4..46cf4678331 100644
--- a/base/est/src/main/java/org/dogtagpki/est/ESTBackend.java
+++ b/base/est/src/main/java/org/dogtagpki/est/ESTBackend.java
@@ -1,6 +1,5 @@
 package org.dogtagpki.est;
 
-import java.security.cert.X509Certificate;
 import java.util.Optional;
 
 import org.mozilla.jss.netscape.security.pkcs.PKCS10;
@@ -38,7 +37,7 @@ public abstract CertificateChain cacerts(Optional<String> label)
      *
      * @param authzData data returned by the ESTRequestAuthorizer.  May be null.
      */
-    public abstract X509CertImpl simpleenroll(Optional<String> label, PKCS10 csr, Object authzData)
+    public abstract X509CertImpl simpleenroll(Optional<String> label, PKCS10 csr, ESTRequestAuthorizationData authzData, Object authzResult)
         throws PKIException;
 
     /**
@@ -46,7 +45,7 @@ public abstract X509CertImpl simpleenroll(Optional<String> label, PKCS10 csr, Ob
      *
      * @param authzData data returned by the ESTRequestAuthorizer.  May be null.
      */
-    public abstract X509CertImpl simplereenroll(Optional<String> label, PKCS10 csr, Object authzData)
+    public abstract X509CertImpl simplereenroll(Optional<String> label, PKCS10 csr, ESTRequestAuthorizationData authzData, Object authzResult)
         throws PKIException;
 
 }
diff --git a/base/est/src/main/java/org/dogtagpki/est/ESTServlet.java b/base/est/src/main/java/org/dogtagpki/est/ESTServlet.java
index 27bb5188451..9199b975808 100644
--- a/base/est/src/main/java/org/dogtagpki/est/ESTServlet.java
+++ b/base/est/src/main/java/org/dogtagpki/est/ESTServlet.java
@@ -109,7 +109,7 @@ private byte[] enroll(Optional<String> label, ESTRequestAuthorizationData authzD
 
         Object authzResult = getRequestAuthorizer().authorizeSimpleenroll(authzData, csr);
 
-        X509Certificate cert = getBackend().simpleenroll(label, csr, authzResult);
+        X509Certificate cert = getBackend().simpleenroll(label, csr, authzData, authzResult);
         return certResponse(cert);
     }
 
@@ -129,7 +129,7 @@ private byte[] reenroll(Optional<String> label, ESTRequestAuthorizationData auth
 
         Object authzResult = getRequestAuthorizer().authorizeSimplereenroll(authzData, csr, toBeRenewed);
 
-        X509Certificate cert = getBackend().simplereenroll(label, csr, authzResult);
+        X509Certificate cert = getBackend().simplereenroll(label, csr, authzData,  authzResult);
         return certResponse(cert);
     }
 
diff --git a/base/server/src/main/resources/UserMessages.properties b/base/server/src/main/resources/UserMessages.properties
index 9c0a6424c31..cc9094b044e 100644
--- a/base/server/src/main/resources/UserMessages.properties
+++ b/base/server/src/main/resources/UserMessages.properties
@@ -1041,6 +1041,9 @@ CMS_PROFILE_CERTIFICATE_POLICIES_EMPTY_CPSURI=Empty CPSuri
 CMS_PROFILE_REQUESTOR_NAME=Requestor Name
 CMS_PROFILE_REQUESTOR_EMAIL=Requestor Email
 CMS_PROFILE_REQUESTOR_PHONE=Requestor Phone
+CMS_PROFILE_RA_CLIENT_UID=RA client uid
+CMS_PROFILE_RA_CLIENT_NAME=RA client Name
+CMS_PROFILE_RA_CLIENT_CERTIFICATE=RA client certificate
 CMS_PROFILE_REQ_SAN_TYPE=Request Subject Alternative Name Extension Type
 CMS_PROFILE_REQ_SAN_PATTERN=Request Subject Alternative Name Extension Pattern
 CMS_PROFILE_SERVER_KEYGEN_P12PASSWORD=Server-Side Key Generation PKCS#12 Password
@@ -1076,6 +1079,8 @@ CMS_PROFILE_INPUT_SERIAL_NUM_NAME=Serial Number of Certificate to Renew
 CMS_PROFILE_INPUT_SERIAL_NUM_TEXT=Serial Number of Certificate to Renew
 CMS_PROFILE_INPUT_SUBMITTER_NAME=Requestor Information
 CMS_PROFILE_INPUT_SUBMITTER_TEXT=Requestor Information
+CMS_PROFILE_INPUT_RA_CLIENT_AUTH_NAME=RA Client authentication Information
+CMS_PROFILE_INPUT_RA_CLIENT_AUTH_TEXT=RA Client authentication Information
 CMS_PROFILE_INPUT_GENERIC_NAME_NAME=Generic Input
 CMS_PROFILE_INPUT_GENERIC_NAME_TEXT=Generic Input
 CMS_PROFILE_GI_PARAM_NAME=Parameter Name


Reviews:
user: login: edewata
body: Just one minor suggestion, but it looks good to me. I'll defer to @ladycfu for the final review.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T14:00:19Z
user: login: fmarco76
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T14:51:47Z
user: login: edewata
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T17:08:23Z
user: login: fmarco76
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T17:12:15Z
user: login: edewata
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T17:38:12Z
user: login: ladycfu
body: LGTM, if tested to work.  Just a couple suggestions.  Thanks.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T18:21:56Z
user: login: fmarco76
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-19T08:29:25Z
user: login: fmarco76
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-19T08:39:33Z
user: login: edewata
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T14:45:54Z
user: login: edewata
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T14:50:04Z
user: login: ladycfu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T16:40:08Z
user: login: ladycfu
body: LGTM (if tested to work)
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T16:51:32Z
user: login: fmarco76
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-19T17:29:22Z

Review comments:
diff_hunk: @@ -191,14 +191,28 @@ private X509CertImpl issueCertificate(Optional<String> label, PKCS10 pkcs10)
             CertEnrollmentRequest certEnrollmentRequest = certClient.getEnrollmentTemplate(profile);
 
             for (ProfileInput input : certEnrollmentRequest.getInputs()) {
-                ProfileAttribute typeAttr = input.getAttribute("cert_request_type");
-                if (typeAttr != null) {
-                    typeAttr.setValue("pkcs10");
+                logger.debug("Check input: {}", input.getClassId());
+                if (input.getClassId().equals("certReqInputImpl")) {
+                    ProfileAttribute typeAttr = input.getAttribute("cert_request_type");
+                    if (typeAttr != null) {
+                        typeAttr.setValue("pkcs10");
+                    }
+
+                    ProfileAttribute csrAttr = input.getAttribute("cert_request");
+                    if (csrAttr != null) {
+                        csrAttr.setValue(Utils.base64encodeSingleLine(pkcs10.toByteArray()));
+                    }
                 }
-
-                ProfileAttribute csrAttr = input.getAttribute("cert_request");
-                if (csrAttr != null) {
-                    csrAttr.setValue(Utils.base64encodeSingleLine(pkcs10.toByteArray()));
+                if (input.getClassId().equals("submitterInfoInputImpl")) {
path: base/est/src/main/java/org/dogtagpki/est/DogtagRABackend.java
user: login: edewata
body: I'd suggest to use an `else if` here to signify that only one of these clauses will be executed for each `input`.
created_at: 2025-05-15T13:59:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -191,14 +191,28 @@ private X509CertImpl issueCertificate(Optional<String> label, PKCS10 pkcs10)
             CertEnrollmentRequest certEnrollmentRequest = certClient.getEnrollmentTemplate(profile);
 
             for (ProfileInput input : certEnrollmentRequest.getInputs()) {
-                ProfileAttribute typeAttr = input.getAttribute("cert_request_type");
-                if (typeAttr != null) {
-                    typeAttr.setValue("pkcs10");
+                logger.debug("Check input: {}", input.getClassId());
+                if (input.getClassId().equals("certReqInputImpl")) {
+                    ProfileAttribute typeAttr = input.getAttribute("cert_request_type");
+                    if (typeAttr != null) {
+                        typeAttr.setValue("pkcs10");
+                    }
+
+                    ProfileAttribute csrAttr = input.getAttribute("cert_request");
+                    if (csrAttr != null) {
+                        csrAttr.setValue(Utils.base64encodeSingleLine(pkcs10.toByteArray()));
+                    }
                 }
-
-                ProfileAttribute csrAttr = input.getAttribute("cert_request");
-                if (csrAttr != null) {
-                    csrAttr.setValue(Utils.base64encodeSingleLine(pkcs10.toByteArray()));
+                if (input.getClassId().equals("submitterInfoInputImpl")) {
path: base/est/src/main/java/org/dogtagpki/est/DogtagRABackend.java
user: login: fmarco76
body: Actually, all the values, if available, will be submitted to the CA so there is not the limitation to only one. I have not yet implemented the CA handling for these but I do not see a reason to limit to a single attribute.
created_at: 2025-05-15T14:51:47Z
author_association: MEMBER
diff_hunk: @@ -191,14 +191,28 @@ private X509CertImpl issueCertificate(Optional<String> label, PKCS10 pkcs10)
             CertEnrollmentRequest certEnrollmentRequest = certClient.getEnrollmentTemplate(profile);
 
             for (ProfileInput input : certEnrollmentRequest.getInputs()) {
-                ProfileAttribute typeAttr = input.getAttribute("cert_request_type");
-                if (typeAttr != null) {
-                    typeAttr.setValue("pkcs10");
+                logger.debug("Check input: {}", input.getClassId());
+                if (input.getClassId().equals("certReqInputImpl")) {
+                    ProfileAttribute typeAttr = input.getAttribute("cert_request_type");
+                    if (typeAttr != null) {
+                        typeAttr.setValue("pkcs10");
+                    }
+
+                    ProfileAttribute csrAttr = input.getAttribute("cert_request");
+                    if (csrAttr != null) {
+                        csrAttr.setValue(Utils.base64encodeSingleLine(pkcs10.toByteArray()));
+                    }
                 }
-
-                ProfileAttribute csrAttr = input.getAttribute("cert_request");
-                if (csrAttr != null) {
-                    csrAttr.setValue(Utils.base64encodeSingleLine(pkcs10.toByteArray()));
+                if (input.getClassId().equals("submitterInfoInputImpl")) {
path: base/est/src/main/java/org/dogtagpki/est/DogtagRABackend.java
user: login: edewata
body: I mean, a request can have multiple inputs, but a single `input` can only be a `certReqInputImpl` or a `submitterInfoInputImpl` but not both at the same time, so I was suggesting to use `else if` instead of multiple `if` statements. Regardless, this is just a minor suggestion.
created_at: 2025-05-15T17:08:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -191,14 +191,28 @@ private X509CertImpl issueCertificate(Optional<String> label, PKCS10 pkcs10)
             CertEnrollmentRequest certEnrollmentRequest = certClient.getEnrollmentTemplate(profile);
 
             for (ProfileInput input : certEnrollmentRequest.getInputs()) {
-                ProfileAttribute typeAttr = input.getAttribute("cert_request_type");
-                if (typeAttr != null) {
-                    typeAttr.setValue("pkcs10");
+                logger.debug("Check input: {}", input.getClassId());
+                if (input.getClassId().equals("certReqInputImpl")) {
+                    ProfileAttribute typeAttr = input.getAttribute("cert_request_type");
+                    if (typeAttr != null) {
+                        typeAttr.setValue("pkcs10");
+                    }
+
+                    ProfileAttribute csrAttr = input.getAttribute("cert_request");
+                    if (csrAttr != null) {
+                        csrAttr.setValue(Utils.base64encodeSingleLine(pkcs10.toByteArray()));
+                    }
                 }
-
-                ProfileAttribute csrAttr = input.getAttribute("cert_request");
-                if (csrAttr != null) {
-                    csrAttr.setValue(Utils.base64encodeSingleLine(pkcs10.toByteArray()));
+                if (input.getClassId().equals("submitterInfoInputImpl")) {
path: base/est/src/main/java/org/dogtagpki/est/DogtagRABackend.java
user: login: fmarco76
body: I was understanding that the `else if` was for the attributes. I get now.  Thanks
created_at: 2025-05-15T17:12:15Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,104 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
path: base/ca/src/main/java/com/netscape/cms/profile/input/ClientAuthInfoInput.java
user: login: ladycfu
body: I'm not sure how exactly copy rights works.  Should this be 2025? @edewata do you know?
created_at: 2025-05-16T16:39:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6,7 +6,8 @@ desc=EST service certificate profile
 enable=true
 input.i1.class_id=certReqInputImpl
 input.i2.class_id=submitterInfoInputImpl
-input.list=i1,i2
+input.i3.class_id=clientAuthInfoInputImpl
+input.list=i1,i2,i3
path: base/ca/shared/profiles/ca/estServiceCert.cfg
user: login: edewata
body: Since EST is officially supported in PKI 11.6, we probably should provide an upgrade script to apply these changes to existing instances.
created_at: 2025-05-16T17:38:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,104 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.profile.input;
+
+import java.util.Locale;
+import java.util.Map;
+
+import com.netscape.certsrv.profile.EProfileException;
+import com.netscape.certsrv.property.Descriptor;
+import com.netscape.certsrv.property.IDescriptor;
+import com.netscape.cms.profile.common.Profile;
+import com.netscape.cms.profile.common.ProfileInputConfig;
+import com.netscape.cmscore.apps.CMS;
+import com.netscape.cmscore.request.Request;
+
+/**
+ * This class implements the client authentication information
+ * input that collects RA client information such as uid, name,
path: base/ca/src/main/java/com/netscape/cms/profile/input/ClientAuthInfoInput.java
user: login: ladycfu
body: It's good that "RA" is mentioned in the comment here.  However, I'm wondering if we need to make it more clear by changing the name of this input plugin code as well as other parameters to make it more clear what these are for.  Would something like estClientAuthInfoInput.java (or "raClientAuthInfoInput.java") do? And perhaps any "external facing" ones such as the UID, NAME, and CERT defined below (e.g. est_client_uid, est_client_name, est_client_certificate)?  No need to change the internal names "UID" etc. Just the definition ("client_uid") that's being used externally.  Use "ra" instead of "est" if they are likely to be shared by other types of RAs.
created_at: 2025-05-16T18:12:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,104 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.profile.input;
+
+import java.util.Locale;
+import java.util.Map;
+
+import com.netscape.certsrv.profile.EProfileException;
+import com.netscape.certsrv.property.Descriptor;
+import com.netscape.certsrv.property.IDescriptor;
+import com.netscape.cms.profile.common.Profile;
+import com.netscape.cms.profile.common.ProfileInputConfig;
+import com.netscape.cmscore.apps.CMS;
+import com.netscape.cmscore.request.Request;
+
+/**
+ * This class implements the client authentication information
+ * input that collects RA client information such as uid, name,
path: base/ca/src/main/java/com/netscape/cms/profile/input/ClientAuthInfoInput.java
user: login: ladycfu
body: and CMS_PROFILE_CLIENT_UID -> CMS_PROFILE_EST_CLIENT_UID and the other two params, etc.
created_at: 2025-05-16T18:15:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,104 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.profile.input;
+
+import java.util.Locale;
+import java.util.Map;
+
+import com.netscape.certsrv.profile.EProfileException;
+import com.netscape.certsrv.property.Descriptor;
+import com.netscape.certsrv.property.IDescriptor;
+import com.netscape.cms.profile.common.Profile;
+import com.netscape.cms.profile.common.ProfileInputConfig;
+import com.netscape.cmscore.apps.CMS;
+import com.netscape.cmscore.request.Request;
+
+/**
+ * This class implements the client authentication information
+ * input that collects RA client information such as uid, name,
path: base/ca/src/main/java/com/netscape/cms/profile/input/ClientAuthInfoInput.java
user: login: ladycfu
body: need @edewata 's opinion too. 
created_at: 2025-05-16T18:20:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,104 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.profile.input;
+
+import java.util.Locale;
+import java.util.Map;
+
+import com.netscape.certsrv.profile.EProfileException;
+import com.netscape.certsrv.property.Descriptor;
+import com.netscape.certsrv.property.IDescriptor;
+import com.netscape.cms.profile.common.Profile;
+import com.netscape.cms.profile.common.ProfileInputConfig;
+import com.netscape.cmscore.apps.CMS;
+import com.netscape.cmscore.request.Request;
+
+/**
+ * This class implements the client authentication information
+ * input that collects RA client information such as uid, name,
path: base/ca/src/main/java/com/netscape/cms/profile/input/ClientAuthInfoInput.java
user: login: fmarco76
body: Yes, I will modify the name to with RA prefix since this could be not limited to EST.
created_at: 2025-05-19T08:29:24Z
author_association: MEMBER
diff_hunk: @@ -6,7 +6,8 @@ desc=EST service certificate profile
 enable=true
 input.i1.class_id=certReqInputImpl
 input.i2.class_id=submitterInfoInputImpl
-input.list=i1,i2
+input.i3.class_id=clientAuthInfoInputImpl
+input.list=i1,i2,i3
path: base/ca/shared/profiles/ca/estServiceCert.cfg
user: login: fmarco76
body: Not sure if we have to migrate. The initial goal is to make possible to define policies in the CA for the certificate but it should not be mandatory and current setup should work without changes.

If we decide to drop the current EST subsystem policies and configure only in the CA than we must implement a migration. Therefore, we can decide in a following PR.
created_at: 2025-05-19T08:39:32Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,104 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
path: base/ca/src/main/java/com/netscape/cms/profile/input/ClientAuthInfoInput.java
user: login: edewata
body: For new code I'd suggest to use SPDX license without a copyright year like this:
https://github.com/dogtagpki/pki/blob/master/base/server/src/main/java/com/netscape/cmscore/apps/EngineConfig.java#L1-L5

created_at: 2025-05-19T14:45:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,104 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.profile.input;
+
+import java.util.Locale;
+import java.util.Map;
+
+import com.netscape.certsrv.profile.EProfileException;
+import com.netscape.certsrv.property.Descriptor;
+import com.netscape.certsrv.property.IDescriptor;
+import com.netscape.cms.profile.common.Profile;
+import com.netscape.cms.profile.common.ProfileInputConfig;
+import com.netscape.cmscore.apps.CMS;
+import com.netscape.cmscore.request.Request;
+
+/**
+ * This class implements the client authentication information
+ * input that collects RA client information such as uid, name,
path: base/ca/src/main/java/com/netscape/cms/profile/input/ClientAuthInfoInput.java
user: login: edewata
body: sounds good to me
created_at: 2025-05-19T14:50:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6,7 +6,8 @@ desc=EST service certificate profile
 enable=true
 input.i1.class_id=certReqInputImpl
 input.i2.class_id=submitterInfoInputImpl
-input.list=i1,i2
+input.i3.class_id=clientAuthInfoInputImpl
+input.list=i1,i2,i3
path: base/ca/shared/profiles/ca/estServiceCert.cfg
user: login: ladycfu
body: It is something to consider.  The original implementation did not allow for agent-approved enrollments.
created_at: 2025-05-19T16:40:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6,7 +6,8 @@ desc=EST service certificate profile
 enable=true
 input.i1.class_id=certReqInputImpl
 input.i2.class_id=submitterInfoInputImpl
-input.list=i1,i2
+input.i3.class_id=clientAuthInfoInputImpl
+input.list=i1,i2,i3
path: base/ca/shared/profiles/ca/estServiceCert.cfg
user: login: fmarco76
body: In the original case the approval is done by the RA after the enrolment so there are multiple interactions between EST and CA during a client `simpleenroll` request. EST does the following operation with the CA:

1. send the request to the CA,
2. verify the status,
3. approve the request,
4. retrieve the certificate.

With the new approach the point 3 is not needed.
created_at: 2025-05-19T17:29:22Z
author_association: MEMBER

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-05-19T15:57:44Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=dogtagpki_pki&pullRequest=5090) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=dogtagpki_pki&pullRequest=5090&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=dogtagpki_pki&pullRequest=5090&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=dogtagpki_pki&pullRequest=5090&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=dogtagpki_pki&pullRequest=5090&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [37.6% Duplication on New Code](https://sonarcloud.io/component_measures?id=dogtagpki_pki&pullRequest=5090&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=dogtagpki_pki&pullRequest=5090)


author_association: NONE
user: login: fmarco76
created_at: 2025-05-20T07:20:11Z
body: @edewata @ladycfu Thanks!
author_association: MEMBER