Dogtag profile definitions

In the previous post I began an exploration of Dogtag’s certificate profiles feature by looking at the certificate request process and the relationship between PKCS #10 CSRs and Dogtag certificate enrolment requests, which are used to submit CSRs in the context of a profile. In this post we will look at how Dogtag profiles are defined and learn a little about how Dogtag uses them in the certificate enrolment process.

Each instance of Dogtag or Certificate Server starts out with a default set of profiles; these are found in the Dogtag instance directory in /var/lib/pki/<instance-name>/ca/profiles/ca/. There are dozens of profiles, but since we are already familiar with caServerCert let’s open up caServerCert.cfg and have a look:

desc=This certificate profile is for enrolling server certificates.
visible=true
enable=true
enableBy=admin
auth.class_id=
name=Manual Server Certificate Enrollment
input.list=i1,i2
input.i1.class_id=certReqInputImpl
input.i2.class_id=submitterInfoInputImpl
output.list=o1
output.o1.class_id=certOutputImpl
policyset.list=serverCertSet
policyset.serverCertSet.list=1,2,3,4,5,6,7,8
policyset.serverCertSet.1.constraint.class_id=subjectNameConstraintImpl
policyset.serverCertSet.1.constraint.name=Subject Name Constraint
policyset.serverCertSet.1.constraint.params.pattern=.*CN=.*
policyset.serverCertSet.1.constraint.params.accept=true
policyset.serverCertSet.1.default.class_id=userSubjectNameDefaultImpl
policyset.serverCertSet.1.default.name=Subject Name Default
policyset.serverCertSet.1.default.params.name=
policyset.serverCertSet.2.constraint.class_id=validityConstraintImpl
policyset.serverCertSet.2.constraint.name=Validity Constraint
policyset.serverCertSet.2.constraint.params.range=720
policyset.serverCertSet.2.constraint.params.notBeforeCheck=false
policyset.serverCertSet.2.constraint.params.notAfterCheck=false
policyset.serverCertSet.2.default.class_id=validityDefaultImpl
policyset.serverCertSet.2.default.name=Validity Default
policyset.serverCertSet.2.default.params.range=720
policyset.serverCertSet.2.default.params.startTime=0
policyset.serverCertSet.3.constraint.class_id=keyConstraintImpl
policyset.serverCertSet.3.constraint.name=Key Constraint
policyset.serverCertSet.3.constraint.params.keyType=-
policyset.serverCertSet.3.constraint.params.keyParameters=1024,2048,3072,4096,nistp256,nistp384,nistp521
policyset.serverCertSet.3.default.class_id=userKeyDefaultImpl
policyset.serverCertSet.3.default.name=Key Default
... (on it goes, through to policyset.serverCertSet.8.*)

There is an obvious relationship between the profile configuration, the certificate enrolment request template retrieved via pki cert-request-profile-show and the behaviour of the CA when submitting or approving enrolment requests. For example, there are two inputs: one for a certificate request (PKCS #10 CSR) and one for submitter information. These are the same two inputs we had to fill out in the XML certificate enrolment request template. And there are constraint declarations; again, we have observed the effects of these declarations when non-conformant enrolment requests were rejected.

Let’s break down the profile configuration. The top-level settings such as name, desc and enable are self-explanatory. Moving down, we see the input.list key specifying the list i1,i2, followed by keys input.i1.class_id and input.i2.class_id. This pattern of foo.list=f1,f2,.. followed by foo.f1..., foo.f2..., and so on also occurs further down for output and policyset, and seems to provide a simple, deterministic way to read ordered declarations from the profile configuration.

The class_id key also occurs in the output and policy set contexts. To what does its value refer? The file /etc/pki/<instance-name>/ca/registry.cfg holds the answer, mapping the values in the profile configuration to Java classes. These classes implement interfaces relevant to their role in the profile system: IProfileInput, IProfileOutput, IPolicyConstraint for inputs, outputs and policy constraints, and IPolicyDefault and ICertInfoPolicyDefault for policy defaults.

Whilst inputs and outputs have no further configuration beyond the class_id, policy set constraints and defaults are parameterised, with each class offering named parameters that relate to its function. For example, subjectNameConstraintImpl has parameters pattern (a regular expression) and accept (boolean; I infer that this controls whether to accept or reject a CSR on match). When a profile is used, e.g. to generate an enrolment request template, submit an enrolment request, or to generate a certificate, Dogtag instantiates the classes according to the profile configuration and uses their behaviours to carry out the requested action – or to decide how or whether to carry it out.

Armed with an understanding of how profiles are configured, let’s try and define a new profile. My first action was to simply copy caServerCert.cfg to caServerCertTest.cfg (ensuring the new file can be read by pkiuser). The name and desc values were changed and the subject name constraint pattern was updated to .*CN=test.* to make it easy to verify that the new profile is being used correctly. Let’s restart the server (the service name depends on the Dogtag instance name) and see if Dogtag has learned about the new profile:

$ sudo systemctl restart pki-tomcatd@pki-tomcat.service
$ pki cert-request-profile-show caServerCertTest
BadRequestException: Cannot provide enrollment template for profile `caServerCertTest`.  Profile not found

There must be more to configure. A thorough search turns up a few references to caServerCert in /etc/pki/<instance-name>/ca/CS.cfg:

...
profile.caServerCert.class_id=caEnrollImpl
profile.caServerCert.config=/var/lib/pki/<instance-name>/ca/profiles/ca/caServerCert.cfg
...
profile.list=caUserCert,caECUserCert,...,caServerCert,...
...

We have found what appears to be the canonical list of profiles and furthermore can see that the full path to the profile is configurable and that each profile specifies a class_id. The class_id values that can be used here appear in the same registry.cfg we learned about above. The classes referred to implement the IProfile interface.

After adding the profile.caServerCertTest configuration, appending caServerCertTest to profile.list and restarting Dogtag again, we can finally use our new profile:

$ pki cert-request-profile-show caServerCertTest
--------------------------------------------------
Enrollment Template for Profile "caServerCertTest"
--------------------------------------------------
  Profile ID: caServerCertTest
  Renewal: false

  Input ID: i1
  Name: Certificate Request Input
  Class: certReqInputImpl

    Attribute Name: cert_request_type
    Attribute Description: Certificate Request Type
    Attribute Syntax: cert_request_type

    Attribute Name: cert_request
    Attribute Description: Certificate Request
    Attribute Syntax: cert_request

  Input ID: i2
  Name: Requestor Information
  Class: submitterInfoInputImpl

    Attribute Name: requestor_name
    Attribute Description: Requestor Name
    Attribute Syntax: string

    Attribute Name: requestor_email
    Attribute Description: Requestor Email
    Attribute Syntax: string

    Attribute Name: requestor_phone
    Attribute Description: Requestor Phone
    Attribute Syntax: string

Adding the --output <filename> argument to the above command downloads the certificate enrolment request template for our new caServerCertTest profile. Using it to submit a CSR with a subject common name (CN) not starting with test. results in summary rejection as hoped, and submission succeeds when the CN does satisfy our constraint.

In the next post we’ll dive into some code to look at how inputs, constraints and defaults are actually implemented, and perhaps implement one or two of our own.

Leave a Reply

Your email address will not be published. Required fields are marked *