This post records the results of some experimentation with the Dogtag API. Specifically, we will show how to authenticate against the API using credentials that are automatically generated by FreeIPA installation, how to use debug tools distributed with certmonger to issue certificates via the API, and a method of tweaking the created cert via the API parameters passed.

Acquiring the tool

We will be using the submit-d tool, included in the certmonger source distribution but not the binary packages. First we download the source and build it:

$ git clone git://git.fedorahosted.org/git/certmonger.git
$ cd certmonger
$ sudo dnf install dbus-devel gettext-devel libidn-devel
$ ./autogen.sh
$ make

Authentication setup

FreeIPA uses a client certificate stored in the NSS database /etc/httpd/alias to authenticate to Dogtag. Unfortunately, this database uses the older DBM format, while the tool we will be using requires the newer SQLite format. So first we must create a new database and copy the cert we need into it, via a PKCS12 file:

mkdir /tmp/certs
certutil -N -d sql:/tmp/certs
sudo pk12util -o ipaCert.p12 -n ipaCert -d /etc/httpd/alias -k /etc/httpd/alias/pwdfile.txt
sudo pk12util -i ipaCert.p12 -n ipaCert -d sql:/tmp/certs

At all password prompts, hit enter. We now have two certs in the file - ipaCert, the client cert we will use for authentication, and the CA cert that signs all of the certs issued by FreeIPA:

[admin@vm-166 certs]$ certutil -L -d sql:/tmp/certs

Certificate Nickname                                         Trust Attributes
                                                             SSL,S/MIME,JAR/XPI

ipaCert                                                      u,u,u
DOMAIN.EXAMPLE.COM IPA CA                                    ,,

Mark the CA cert as trusted, otherwise the client will refuse to talk to the server:

certutil -M -t TC,, -d sql:/tmp/certs -n 'DOMAIN.EXAMPLE.COM IPA CA'

Making requests

Generate a keypair and a CSR to submit to the CA. The openssl req command will prompt for the certificate subject; fill it out however you like.

$ openssl genrsa -out test.key
$ openssl req -new -key /tmp/certs/test.key -out /tmp/certs/test.req

Use the submit-d tool to submit the request to Dogtag. If we use the caIPAserviceCert template, the request goes through immediately and we are presented with a certificate:

$ src/submit-d -u https://server.example.com:8443/ca/ee/ca -U https://server.example.com:8443/ca/agent/ca \
    -vv -d /tmp/certs -C ipaCert -a -T caIPAserviceCert -s /tmp/certs/test.req

We can see from the output that the tool makes a POST request to the profileSubmit endpoint of the server.

On the other hand, if we use a non-IPA cert such as caServerCert, the tool makes the same call but the request will be deferred until approved:

$ src/submit-d -u https://server.example.com:8443/ca/ee/ca -U https://server.example.com:8443/ca/agent/ca \
    -vv -d /tmp/certs -C ipaCert -a -T caServerCert -s /tmp/certs/test.req

In this case, a requestId is provided; we will use this to approve the request:

result = "<?xml version="1.0" encoding="UTF-8" standalone="no"?><XMLResponse><Status>2</Status><Error>Request Deferred - {0}</Error><RequestId>  31</RequestId></XMLResponse>"
error: Request Deferred - {0}
status: 2
requestId: 31

We can approve the request with the -A flag and receive the certificate:

$ src/submit-d -u https://server.example.com:8443/ca/ee/ca -U https://server.example.com:8443/ca/agent/ca \
    -vv -d /tmp/certs -C ipaCert -a -T caServerCert -A 31

Tweaking certificate parameters

If we look through the output of the approval command run above, we see a call to the profileProcess endpoint on the Dogtag server. Interestingly, this call includes many of the parameters of the certificate:

GET /ca/agent/ca/profileProcess?requestId=31&op=approve&xml=true&name=CN%3Dserver.example.com%2CO%3DDOMAIN.EXAMPLE.COM&notBefore=2016-06-13+02%3A50%3A46&notAfter=2018-06-03+02%3A50%3A46&authInfoAccessCritical=false&authInfoAccessGeneralNames=Record+%230%0AMethod%3A1.3.6.1.5.5.7.48.1%0ALocation+Type%3AURIName%0ALocation%3Ahttp%3A%2F%2Fserver.example.com%3A80%2Fca%2Focsp%0AEnable%3Atrue&keyUsageCritical=true&keyUsageDigitalSignature=true&keyUsageNonRepudiation=true&keyUsageKeyEncipherment=true&keyUsageDataEncipherment=true&keyUsageKeyAgreement=false&keyUsageKeyCertSign=false&keyUsageCrlSign=false&keyUsageEncipherOnly=false&keyUsageDecipherOnly=false&exKeyUsageCritical=false&exKeyUsageOIDs=1.3.6.1.5.5.7.3.1%2C1.3.6.1.5.5.7.3.2&signingAlg=SHA256withRSA HTTP/1.1

The tool gets these parameters by parsing the output of a call to the profileReview endpoint. However, we will just re-use the same values, making a small modification to the name parameter. What happens if we submit the request again, and then approve it with the modified parameters?

src/submit-d -u https://server.example.com:8443/ca/ee/ca -U https://server.example.com:8443/ca/agent/ca \
    -vv -d /tmp/certs -C ipaCert -a -T caServerCert -A 32 \
    -V 'name=CN%3Dnewname%2CO%3DEXAMPLE.COM&notBefore=2016-06-13+02%3A50%3A46&notAfter=2018-06-03+02%3A50%3A46&authInfoAccessCritical=false&authInfoAccessGeneralNames=Record+%230%0AMethod%3A1.3.6.1.5.5.7.48.1%0ALocation+Type%3AURIName%0ALocation%3Ahttp%3A%2F%2Fserver.example.com%3A80%2Fca%2Focsp%0AEnable%3Atrue&keyUsageCritical=true&keyUsageDigitalSignature=true&keyUsageNonRepudiation=true&keyUsageKeyEncipherment=true&keyUsageDataEncipherment=true&keyUsageKeyAgreement=false&keyUsageKeyCertSign=false&keyUsageCrlSign=false&keyUsageEncipherOnly=false&keyUsageDecipherOnly=false&exKeyUsageCritical=false&exKeyUsageOIDs=1.3.6.1.5.5.7.3.1%2C1.3.6.1.5.5.7.3.2&signingAlg=SHA256withRSA'

Our new name shows up in the certificate!

Certificate:
    Data:
        Version:  v3
        Serial Number: 0x1E
        Signature Algorithm: SHA256withRSA - 1.2.840.113549.1.1.11
        Issuer: CN=Certificate Authority,O=DOMAIN.EXAMPLE.COM
        Validity:
            Not Before: Monday, June 13, 2016 2:50:46 AM GMT
            Not  After: Sunday, June 3, 2018 2:50:46 AM GMT
        Subject: CN=newname,O=EXAMPLE.COM