Originally filed as https://pagure.io/freeipa/issue/7347
ipa-server-install should work when a custom RDN is used, when the RDN contains escaped commas. Alternatively, if this is not possible due to interactions with Dogtag code, the documentation should expressly indicate that such escaped values cannot be used.
ipa-server-install
When running ipa-server-install with the --subject-base option to override the default realm name as the organization, a comma that is properly escaped will cause an authentication failure later in the setup script.
--subject-base
One legitimate reason that the RDN would include a comma is a corporation's legal name — for example, "O=Acme\, Inc.,ST=Massachusetts,C=US". According to RFC 4514, commas can be escaped with a prefixed backslash (section 2.4; examples in section 4).
"O=Acme\, Inc.,ST=Massachusetts,C=US"
yum install ipa-server
/etc/hosts
The installation proceeds, but halts with an error at step 25 of the CA setup with the following message:
Configuring certificate server (pki-tomcatd). Estimated time: 3 minutes [1/29]: configuring certificate server instance [2/29]: exporting Dogtag certificate store pin [3/29]: stopping certificate server instance to update CS.cfg [2/29]: exporting Dogtag certificate store pin [3/29]: stopping certificate server instance to update CS.cfg [4/29]: backing up CS.cfg [5/29]: disabling nonces [6/29]: set up CRL publishing [7/29]: enable PKIX certificate path discovery and validation [8/29]: starting certificate server instance [9/29]: configure certmonger for renewals [10/29]: requesting RA certificate from CA [11/29]: setting up signing cert profile [12/29]: setting audit signing renewal to 2 years [13/29]: restarting certificate server [14/29]: publishing the CA certificate [15/29]: adding RA agent as a trusted user [16/29]: authorizing RA to modify profiles [17/29]: authorizing RA to manage lightweight CAs [18/29]: Ensure lightweight CAs container exists [19/29]: configure certificate renewals [20/29]: configure Server-Cert certificate renewal [21/29]: Configure HTTP to proxy connections [22/29]: restarting certificate server [23/29]: updating IPA configuration [24/29]: enabling CA instance [25/29]: migrating certificate profiles to LDAP [error] RemoteRetrieveError: Failed to authenticate to CA REST API ipa.ipapython.install.cli.install_tool(CompatServerMasterInstall): ERROR Failed to authenticate to CA REST API ipa.ipapython.install.cli.install_tool(CompatServerMasterInstall): ERROR The ipa-server-install command failed. See /var/log/ipaserver-install.log for more information
The certificate authority has already been configured at this point. A valid /etc/ipa/ca.crt has already been created, whose issuer and subject names are properly formatted.
/etc/ipa/ca.crt
The installation should succeed.
ipa-server-4.5.0-22.el7.centos.x86_64 ipa-client-4.5.0-22.el7.centos.x86_64 389-ds-base-1.3.6.1-24.el7_4.x86_64 pki-ca-10.4.1-17.el7_4.noarch krb5-server-1.15.1-8.el7.x86_64
Log file locations: https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Linux_Domain_Identity_Authentication_and_Policy_Guide/config-files-logs.html Troubleshooting guide: https://www.freeipa.org/page/Troubleshooting
Here's the generated CA certificate, showing that the base DN has been properly applied (meaning that the escaped comma was properly processed here).
The contents of /var/log/pki/pki-tomcat/ca/system show that it was "IPA RA" that failed to authenticate — and reveal the jumbled subject name given to that certificate:
/var/log/pki/pki-tomcat/ca/system
0.localhost-startStop-1 - [04/Jan/2018:05:15:52 UTC] [13] [3] authz instance DirAclAuthz initialization failed and skipped, error=Property internaldb.ldapconn.port missing value 0.http-bio-8443-exec-3 - [04/Jan/2018:05:17:03 UTC] [3] [3] Cannot build CA chain. Error java.security.cert.CertificateException: Certificate is not a PKCS #11 certificate 0.http-bio-8443-exec-3 - [04/Jan/2018:05:17:06 UTC] [3] [3] CASigningUnit: Object certificate not found. Error Certificate object not found 0.Thread-14 - [04/Jan/2018:05:17:38 UTC] [8] [3] Publishing: Could not publish certificate serial number 0x7. Error Failed to publish using rule: No rules enabled 0.http-bio-8443-exec-3 - [04/Jan/2018:05:18:35 UTC] [6] [3] Cannot authenticate agent with certificate Serial 0x7 Subject DN CN=IPA RA,CN=Inc.,O=Acme\\,ST=Massachusetts,C=US. Error: User not found
Notice: CN=IPA RA,CN=Inc.,O=Acme\\,ST=Massachusetts,C=US
Similarly, /var/log/pki/pki-tomcat/ca/transactions shows that when the IPA RA certificate was first enrolled, the requested distinguished name already had this problem:
/var/log/pki/pki-tomcat/ca/transactions
0.http-bio-8443-exec-5 - [04/Jan/2018:05:17:38 UTC] [20] [1] enrollment reqID 7 fromAgent userID: admin authenticated by certUserDBAuthMgr is completed DN requested: CN=IPA RA,CN=Inc.,O=Acme\\,ST=Massachusetts,C=US cert issued serial number: 0x7 time: 235
I've also attached the dogtag setup log.
I think I've traced it through to a certmonger issue.
How I got there:
1) ipaserver/install/cainstance.py is responsible for this particular enrollment:
reqId = certmonger.request_and_wait_for_cert( certpath=(paths.RA_AGENT_PEM, paths.RA_AGENT_KEY), principal='host/%s' % self.fqdn, subject=str(DN(('CN', 'IPA RA'), self.subject_base)), ... storage="FILE")
This isn't the problem. The assembled DN containing the subject base is fine; ipapython/dn.py smartly accounts for escaping. In the example I gave above, minus the state (to make these examples more convenient to illustrate), the subject is appropriately assembled as ('CN','IPA RA'),('O','Acme\, Inc.'),('C','US').
('CN','IPA RA'),('O','Acme\, Inc.'),('C','US')
2) However, the parameter above is cast back to a string, instead of being passed as a DN object to certmonger.request_and_wait_for_cert().
certmonger.request_and_wait_for_cert()
Once passed to the certmonger module ipalib/install/certmonger.py, it gets switched back to a DN, reversed, and then back to a string again... this "workaround":
subject = str(DN(*reversed(DN(subject))))
Still not the problem. Despite the list operation and type changes, the ipapython/dn.py module is intelligent, so this line reverses the order of AVAs without damaging the escaping. At this point, the subject is still appropriately grouped, just reversed, as ('C','US'),('O','Acme\, Inc.'),('CN','IPA RA').
('C','US'),('O','Acme\, Inc.'),('CN','IPA RA')
3) The Python code eventually sends this still okay DN string, in reversed order, to certmonger over dbus or a socket... something like (string) C=US,O=Acme\, Inc.,CN=IPA RA.
C=US,O=Acme\, Inc.,CN=IPA RA
4) As certmonger#62 says, certmonger implements the subject field differently depending on the destined storage. Here, since storage="FILE", it's going to use the OpenSSL implementation in csrgen-o.c. (Unlike the NSS implementation in csrgen-n.c, which can invoke a library helper function CERT_AsciiToName(), the OpenSSL implementation is forced to do its own parsing of the DN, one AVA at a time...)
storage="FILE"
CERT_AsciiToName()
5) Which brings me to the certmonger source:
/* This isn't really correct, but it will * probably do for now. */ p = entry->cm_template_subject; q = p + strcspn(p, ","); subject = X509_NAME_new(); if (subject != NULL) { while (*p != '\0') { ...
That's it, then; because csrgen-o.c in certmonger naively splits the subject string by commas, all the hard work in ipapython/dn.py was for naught. Despite ipapython/dn.py's intelligent handling of RDN attributes, certmonger just treated it as a string without accounting for escaping or multivalue.
6) Notably, when the code excerpted above splits a string like C=US,O=Acme\, Inc.,CN=IPA RA, it's going to see C=US; O=Acme\; Inc.; CN=IPA RA. And lines 213-218 treat " Inc." as its own common name value:
C=US
O=Acme\
Inc.
CN=IPA RA
X509_NAME_add_entry_by_txt(subject, "CN", astring_type("CN", p, q - p), (unsigned char *) p, q - p, -1, 0);
I'm assuming the OpenSSL library adds its own escaping to the dangling \, resulting in the final, observed subject of CN=IPA RA,CN=Inc.,O=Acme\\,C=US.
\
CN=IPA RA,CN=Inc.,O=Acme\\,C=US
As I see it, the simple workaround for users is to try the \2c escape code for the comma instead — i.e. O=Acme\2c Inc.,C=US, which the naive C code in certmonger won't damage. But this is definitely not an obvious requirement of --subject-base.
\2c
O=Acme\2c Inc.,C=US
A smarter fix might avoid passing the information as a string. certmonger's code avoids the naive comma-delimiter parsing if a subject is provided in DER.
if ((entry->cm_template_subject_der != NULL) && (strlen(entry->cm_template_subject_der) != 0)) { i = strlen(entry->cm_template_subject_der); name = malloc(i); if (name != NULL) { i = cm_store_hex_to_bin(entry->cm_template_subject_der, name, i); nametmp = name; subject = d2i_X509_NAME(NULL, &nametmp, i); } } if ((subject == NULL) && /* ... go on to split by commas ... */
That might be a more optimal way of passing the information from Python to certmonger.
It seems to me that certmonger is re-inventing the wheel here.
certmonger already links in ldap which provides ldap_str2dn() so it should be straightforward to convert the string subject into an LDAP DN and then walk over that to create the X509 subject.
As it turns out it looks like the NSS call CERT_AsciiToName() also does the wrong thing with escaped commas (though it got saved properly).
The LDAP method I came up with ended up being issued as:
template_subject=CN=ipa.example.com,O="Acme, Inc.",ST=Massachusetts,C=US
The NSS method fails to issue with this template_subject:
template_subject=CN=ipa.example.com,O=Acme\, Inc.,ST=Massachusetts,C=US
I'll try to talk to one of the dogtag devs.
After talking with ftweedal this may be a bug either in dogtag, IPA, both and/or certmonger. He is going to do some further investigation. He thinks the CSR generated by NSS looks ok.
When installing with --subject-base 'OU=201801171517,O=Red Hat\, Inc.', the following CSR was generated by certmonger and sent to Dogtag:
--subject-base 'OU=201801171517,O=Red Hat\, Inc.'
MIIDojCCAooCAQAwSzERMA8GA1UECgwIUmVkIEhhdFwxDjAMBgNVBAMTBSBJbmMu MRUwEwYDVQQLDAwyMDE4MDExNzE1MTcxDzANBgNVBAMTBklQQSBSQTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBANZWszfYutCAvkzuuAaks5RsaiE/9SRi eQlB+5ocKMYiwcHc/A7sTmLgiUgECkYLRNawYeD9S0JpvoCIu0u6EvhzWW2QK1Yq t8cz5uUwVN0qxBoW7+hZqwShbhBy1xt4fOgaDUQEQxeNk8Yu7ZNktRaoP80z+NNn C+hqx+tsnKnbf1SCWoUfZqiS9YkxaiMDT8kQU4B/VZC3sUFwV09cBRlYJfRbLs7Z DMpP+34Q22GfXhW2d1Pjzs2/UMl9d4/JQYbWF+WCtKgHDJlXxaE28W2uNV380Jhy lTxKoX1ytpTsubiQGnknai/02Jx35TQNIiRD7d7QnBx0CMpxFb31EqkCAwEAAaCC ARAwKwYJKoZIhvcNAQkUMR4eHAAyADAAMQA4ADAAMQAxADcAMAA1ADIAMAAxADMw geAGCSqGSIb3DQEJDjGB0jCBzzBxBgNVHREBAQAEZzBloCQGCisGAQQBgjcUAgOg FgwUaG9zdC9mMjctMS5pcGEubG9jYWygPQYGKwYBBQICoDMwMaALGwlJUEEuTE9D QUyhIjAgoAMCAQGhGTAXGwRob3N0Gw9mMjctMS5pcGEubG9jYWwwDAYDVR0TAQH/ BAIwADAgBgNVHQ4BAQAEFgQULvYyu7eusMrnBp0oo/VoXZhBunYwKgYJKwYBBAGC NxQCAQEABBoeGABjAGEAUwBlAHIAdgBlAHIAQwBlAHIAdDANBgkqhkiG9w0BAQsF AAOCAQEAqPhcAQcyhUyNcgcf787UCeuCPPkCdGHMsNl1U7WGPEYbZxFedVsvnB2a 9I1Z8kRuwonH3jrhcZ9nkkUDxQ82KOzpeSKfAKoHeYF8FkR0qelQYz4vyeU0s7Sr fVnjIGRoUfHCNKeUD0FSHEWvmoebzLbEkZGBwIhN2fVbhA1LLGWDu6gjEgkQ3Hn4 o/E/y5aSQsX9y65ETmszu9PKz54GWHtpuFvR9cvCqxmpvVVCrVB+RUmwYJ2PXEEk 3R8jh3kq/5g/n+XbmPwtTs7OloKyXwqPNvxj7cpXCF4+utbVXOxfV8gmPzYAhERu Cp9Sag+BnxG5pRhdEU3rmMmvdXKUhQ==
It has ASN.1 DN structure:
11:d=2 hl=2 l= 75 cons: SEQUENCE 13:d=3 hl=2 l= 17 cons: SET 15:d=4 hl=2 l= 15 cons: SEQUENCE 17:d=5 hl=2 l= 3 prim: OBJECT :organizationName 22:d=5 hl=2 l= 8 prim: UTF8STRING :Red Hat\ 32:d=3 hl=2 l= 14 cons: SET 34:d=4 hl=2 l= 12 cons: SEQUENCE 36:d=5 hl=2 l= 3 prim: OBJECT :commonName 41:d=5 hl=2 l= 5 prim: PRINTABLESTRING : Inc. 48:d=3 hl=2 l= 21 cons: SET 50:d=4 hl=2 l= 19 cons: SEQUENCE 52:d=5 hl=2 l= 3 prim: OBJECT :organizationalUnitName 57:d=5 hl=2 l= 12 prim: UTF8STRING :201801171517 71:d=3 hl=2 l= 15 cons: SET 73:d=4 hl=2 l= 13 cons: SEQUENCE 75:d=5 hl=2 l= 3 prim: OBJECT :commonName 80:d=5 hl=2 l= 6 prim: PRINTABLESTRING :IPA RA
Dogtag processes this CSR just fine (for the particular profile used for the IPA RA certificate), but Certmonger generated the CSR wrong.
Looking at the request file under /var/lib/certmonger/requests, I see:
/var/lib/certmonger/requests
template_subject=O=Red Hat\, Inc.,OU=201801171517,CN=IPA RA
So FreeIPA has conveyed the correct Subject DN to Certmonger when creating the request.
Testing with three new file-based (OpenSSL-based) certificate requests created using the following commands:
% getcert request -f /tmp/tmp2.pem -k /tmp/tmp2.key -G rsa -g 1024 -N "o=Acme\, Inc." -I acme1 New signing request "acme1" added. % getcert request -f /tmp/tmp3.pem -k /tmp/tmp3.key -G rsa -g 1024 -N "ou=HR,o=Acme\, Inc." -I acme2 New signing request "acme2" added. % getcert request -f /tmp/tmp4.pem -k /tmp/tmp4.key -G rsa -g 1024 -N "o=Acme\, Inc.,C=AU" -I acme3 New signing request "acme3" added.
Resulted in the following (stringified) DNs in the CSRs (as displayed by openssl req -text):
openssl req -text
O = Acme\\, CN = " Inc." OU = HR, O = Acme\\, CN = " Inc." O = Acme\\, CN = " Inc.", C = AU
All of these are incorrect parses of the string given in -N.
-N
The parser for FILES just looks for comma tokens so is very simplistic. I have a candidate patch which should handle this better.
OK, reviewing the patch.
It ignores multiple AVA RDNs (only takes rdn[0]). If we're already going this far we might as well fix that properly at this time.
rdn[0]
It seems like attribute strings (o, cn, etc) need to be upper cased for X509_NAME_add_entry_by_txt to recognise them. We should do this upper casing. we should probably also check the return value and log if it didn't work, instead of silenty dropping the AVA.
X509_NAME_add_entry_by_txt
@rcritten here's a patch that will apply on top of yours that:
And here's another patch on top of that one, that extracts the X509_NAME creation procedures into separate subroutines:
X509_NAME
Thanks for the patches!
I'd like to wait until we can do an end-to-end install in IPA before pushing these upstream in case we find anything that needs additional changes. I'll do a proper PR along with your patches when we get to that point.
That could be a little while... it seems that there's a bug in 389DS certmap code too, as well as the identified Dogtag and Certmonger issues.
@rcritten there a PR for the 389 fix now: https://pagure.io/389-ds-base/pull-request/49611.
I've tested this now with the patched versions of Dogtag, Certmonger and 389. So I think we can finish reviewing and merge the Certmonger patches hopefully ASAP now.
Aged in oak. Can we re-review this issue and (hopefully) merge soon?
https://pagure.io/certmonger/pull-request/107
New PR (with test; no other changes): https://pagure.io/certmonger/pull-request/108
Fix pushed to master:
master
632fc96c test handling of DNs with escaped chars bf91c284 csrgen-o: extract X509_NAME creation subroutines 47a60740 csrgen-o: handle multi-value RDNs and log dropped AVAs
@rcritten we can close this now. And also could you cut a new release and Fedora build at your earliest convenience?
Metadata Update from @rcritten: - Issue close_status updated to: fixed - Issue status updated to: Closed (was: Open)
Tagged in 0.79.7
Metadata Update from @rcritten: - Issue assigned to rcritten - Issue set to the milestone: 0.79