Tags: freeipa, certificates

Issuing certificates for long hostnames

X.509, specified in RFC 5280, restricts the length of the Common Name (CN) attribute to 64 characters:

X520CommonName ::= DirectoryName (SIZE (1..ub-common-name))
ub-common-name-length INTEGER ::= 64

Although the use of the CN attribute to carry DNS names is deprecated, it is still common practice. Furthermore, FreeIPA still requires the CN to appear in a Certificate Signing Request (CSR) and validates that its value corresponds to the nominated subject principal.

As a consequence of this restriction, when a host or service has a DNS name longer than 64 characters, that name cannot be used as the CN. But it can still be included in the Subject Alternative Name extension, as a dNSName value.

How do we issue such a certificate in FreeIPA? The trick is to add a principal alias whose hostname is 64 characters or shorter. This shorter hostname will be the Common Name attribute value. The full hostname will appear in the Subject Alternative Name extension.

The following sections demonstrate the method. I conclude with an outline of what needs to be done to support certificates with empty Subject DN, which would avoid the problem and this workaround.

Creating a principal with a long hostname

To experiment and verify the workaround, I needed a principal with a hostname longer than 64 characters. The initial attempt failed:

% ipa host-add --force \
    verylongverylongverylongverylongverylongverylonghostname.ipa.local
ipa: ERROR: invalid 'hostname': can be at most 64 characters

FreeIPA has a default maximum hostname length of 64 characters, but this is configurable. After adjusting the limit, adding the host succeeded:

% ipa config-mod --maxhostname 255
  Maximum username length: 32
  Maximum hostname length: 255
  ...

% ipa host-add --force \
    verylongverylongverylongverylongverylongverylonghostname.ipa.local
-------------------------------------------------------------------------------
Added host "verylongverylongverylongverylongverylongverylonghostname.ipa.local"
-------------------------------------------------------------------------------
  Host name: verylongverylongverylongverylongverylongverylonghostname.ipa.local
  Principal name: host/verylongverylongverylongverylongverylongverylonghostname.ipa.local@IPA.LOCAL
  Principal alias: host/verylongverylongverylongverylongverylongverylonghostname.ipa.local@IPA.LOCAL
  ...

Adding the principal alias

For a host principal, use the ipa host-add-principal command to add a principal alias. The alias must also be a host principal, i.e. must have the form host/$hostname:

% ipa host-add-principal \
    verylongverylongverylongverylongverylongverylonghostname.ipa.local \
    host/longhostname.ipa.local
----------------------------------------------------------------------------------------------
Added new aliases to host "verylongverylongverylongverylongverylongverylonghostname.ipa.local"
----------------------------------------------------------------------------------------------
Host name: verylongverylongverylongverylongverylongverylonghostname.ipa.local
Principal alias: host/verylongverylongverylongverylongverylongverylonghostname.ipa.local@IPA.LOCAL,
                 host/longhostname.ipa.local@IPA.LOCAL

For a service principal, use the ipa service-add-principal command. Ensure the principal alias has the same service type as the subject principal’s canonical name (i.e. the value its krbcanonicalname attribute). For example, if the canonical principal name is HTTP/$LONGHOSTNAME, then the principal alias should be HTTP/$SHORTHOSTNAME.

I omitted the realm parts of principal names (the default realm will be added automatically). For the avoidance of doubt, the princpial alias must have the same realm as the canonical principal.

Creating a CSR

There are many different ways to create a CSR. I will give a single example using OpenSSL. The private key already exists (file key.pem).

The configuration file:

% cat longhostname.conf
[ req ]
prompt = no
encrypt_key = no

distinguished_name = dn
req_extensions = exts

[ dn ]
commonName = "longhostname.ipa.local

[ exts ]
subjectAltName=DNS:verylongverylongverylongverylongverylongverylonghostname.ipa.local

Create the CSR:

% openssl req -new -key key.pem \
    -config longhostname.conf -extensions exts \
    > longhostname.csr

Issuing the certificate

Now we can issue the certificate:

% ipa cert-request longhostname.csr \
    --principal host/verylongverylongverylongverylongverylongverylonghostname.ipa.local
  Issuing CA: ipa
  Certificate: MIIE...
  Subject: CN=longhostname.ipa.local,O=IPA.LOCAL 202009291726
  Subject DNS name: verylongverylongverylongverylongverylongverylonghostname.ipa.local,
                    longhostname.ipa.local
  Issuer: CN=Certificate Authority,O=IPA.LOCAL 202009291726
  Not Before: Mon Oct 19 13:46:16 2020 UTC
  Not After: Thu Oct 20 13:46:16 2022 UTC
  Serial number: 11
  Serial number (hex): 0xB

The CN attribute contains the shorter host name, and the SAN extension contains both the long and shorter hostnames. (We did not include the short hostname in the CSR SAN extension, but the CommonNameToSANDefault profile component copied it there).

Supporting SAN-only certificates

This workaround is straightforward but it is not the ideal solution. A better approach is to enhance FreeIPA and Dogtag to support issuing certificates with an empty Subject DN, using only the Subject Alternative Name extension to carry subject information.

RFC 5280 allows an empty Subject DN in a certificate, in which case the certificate must include the SAN extension, which must be marked as critical. RFC 6125 further clarifies that such a certificate is acceptable for use with TLS.

Upstream ticket #5706 requests support for SAN-only certificates. The work will involve:

Creative Commons License
Except where otherwise noted, this work is licensed under a Creative Commons Attribution 4.0 International License .