Certificates_Refactoring#
Overview#
FreeIPA code is using certificates in many different ways, through various API and tools (NSS, openssl, …) The goal of this refactoring is to provide consistent methods to handle certificates, and will consist in 3 different efforts:
Use python-cryptography instead of ipalib.x509 and ipalib.pkcs10 (ticket #6398)
Use certmonger to request certificates during installation (ticket #6433)
Provide a consistent certificate DB API
Design#
Certificate issuance during installation#
During FreeIPA installation, 3 different certificates are requested:
a certificate for the renew agent (CN=IPA RA,O=$DOMAIN) stored in /etc/httpd/alias with the nickname ipaCert
a certificate for the LDAP server (CN=$FQDN,$DOMAIN) stored in /etc/dirsrv/slapd-$DOMAIN) with the nickname Server-Cert
a certificate for the HTTP server (CN=$FQDN,$DOMAIN) stored in /etc/httpd/alias) with the nickname Server-Cert
The methods to obtain those certificates are not consistent but could be unified by using certmonger to process the issuance. Furthermore, the certificates are later tracked by certmonger. The code needs to take into consideration the profile that will be used for each certificate, as well as certmonger’s CA helper responsible for the request and the tracking.
ipaCert#
This certificate is requested early in the installation process, after Dogtag is configured. At this point, Dogtag has created a certificate for ipa-ca-agent in a temporary NSS DB (specified in the pkispawn config file as the parameter pki_client_database_dir) that can be used to request the RA agent cert.
ipaCert must be requested and tracked by dogtag-ipa-ca-renew-agent CA helper, meaning that the helper needs to be modified in order to use the temp cert ipa-ca-agent to communicate with Dogtag. Pseudo-code for the ra request would be the following:
configure dogtag-ipa-ca-renew-agent CA helper with helper-location: /usr/libexec/certmonger/dogtag-ipa-ca-renew-agent-submit
RA request:
temporarily modify dogtag-ipa-ca-renew-agent CA helper to use ipa-ca-agent stored in the temp NSS DB
request ipaCert through certmonger, with the profile caServerCert
restore original values for dogtag-ipa-ca-renew-agent CA helper
It is important to use the profile caServerCert as it does not define auth.instance_id, meaning that it allows submission without authentication.
LDAP/HTTP server certificate#
These certificate must be requested and tracked using IPA CA helper, with the profile caIPAserviceCert. This profile is defined in Dogtag with auth.instance_id=raCertAuth, meaning that the submission must be performed with authentication, using a SSL certificate for a user member of cn=Registration Manager Agents,ou=groups,o=ipaca. The ipaCert certificate can be used in this case. The issue is that IPA is not completely configured at this point and IPA CA helper will not be able to handle the certificate request. To workaround this, we need to temporarily reconfigure IPA CA helper to use /usr/libexec/certmonger/dogtag-submit instead of /usr/libexec/certmonger/ipa-submit. Pseudo code:
temporarily modify IPA CA helper to use dogtag-submit and agent authentication with ipaCert
request Server-Cert through certmonger, with the profile caIPAserviceCert
restore original values for IPA CA helper
Refactor certificate processing code to use python-cryptography#
Using python-nss for certificate processing has several problems, including:
problems with opening multiple NSSDBs
problems with opening a single NSSDB in multiple processes
python-nss bugs and poor error reporting
lots of NSS functionality not exposed by python-nss
It was desired that we should refactor certificate and CSR processing code to use python-cryptography instead of python-nss. This is largely a mechanical procedure. Aspects of this refactoring where substantive changes were required are detailed in the following subsections.
Dealing with Distinguished Names#
Whereas python-nss exposed DNs as strings (in LDAP order),
python-cryptography exposes cryptography.x509.name.Name
objects.
FreeIPA often needs to work with ipapython.dn.DN
objects, as well as
string representations. DN
objects can be stringified, so it was
necessary and sufficient to extend the DN
constructor to accept
Name
objects. When converting a Name
, the constructor consults a
mapping of python-cryptography ObjectIdentifier
values to LDAP
attribute names.
The current version of python-cryptography does not properly handle
multi-value RDNs. This will be fixed in python-cryptography 1.6. Once
v1.6 is available, the DN
constructor should be updated accordingly.
In practice, due to the rarity of multi-value RDNs in practice, and the
fact that “flattened” DNs should still compare equal, the lack of proper
handling is unlikely to cause problems.
Dealing with known OtherName types#
python-cryptography exposes a single type
cryptography.x509.general_name.OtherName
for OtherName GeneralNames.
There are no hooks for informing python-cryptography of more specific
types that you would like to be recognised.
FreeIPA does need to parse and inspect KRBPrincipalName and UPN
OtherName values. We define corresponding subclasses of OtherName
,
which are constructed by application to an OtherName
value, which
perform additional decoding and expose the more specific data through
additional attributes. When processing general names, we provide a
function that is applied a list of
cryptography.x509.general_name.GeneralName
values, and maps
OtherName
values of known types into the corresponding subtype,
returning the resulting list.
Avoiding PKCS #10 friendlyName attribute#
The dogtag-ipa-ca-renew-agent
Certmonger renewal helper needs to
determine the NSSDB nickname of the certificate being renewed.
Certmonger includes this datum in the friendlyName attribute in the
PKCS #10 CSR. python-nss does not provide a way to access this datum, so
we used hand-rolled pyasn1 definitions to decode this information
ourselves. We wished to remove this.
python-cryptography, like python-nss, does not include a way of reading
the friendlyName attribute. Therefore a different approach was taken.
In dogtag-ipa-ca-renew-agent
, using the FreeIPA deployment’s
certificate subject base, we construct a mapping of subject DNs to
NSSDB nicknames. We then use the value of the CERTMONGER_REQ_SUBJECT
environment variable as the key to look up the NSSDB nickname.
All CSR-related pyasn1 definitions and decoding were removed.
Decoding certificate Subject Alternative Name extension#
python-cryptography does successfully decode certificates with
unrecognised critical extensions, because the decoding of extensions
is deferred until the user attempts to access the extensions
attribute (UnrecognisedExtension
will be thrown at this point).
Until such time as python-cryptography provides a way to handle this
scenario, to process the certificate Subject Alternative Name (SAN)
extension, we must decode the TBSCertificate data ourselves.
Using definitions provided by the pyasn1-modules library, we decode
the value of the cryptography.x509.Certificate.tbs_certificate_bytes
attribute and look for the SAN extension. Then for each general name, we
instantiate the relevant cryptography.x509.general_name.GeneralName
subclass (this is a forward-compatiblity measure and ensures commonality
among higher-level functions that process general names). We do not
convert known OtherName types into subclasses of OtherName
at this
point (the function discuss above can be used to do this).