freeipa

FreeIPA is an integrated Identity and Authentication solution for Linux/UNIX networked environments.  |  http://www.freeipa.org/

#7482 ipa-getcert rekey no longer revokes the old key

Created 5 months ago by cheimes
Modified 3 months ago

Issue

The command ipa-getcert rekey no longer revokes the old certificate.

Steps to Reproduce

  1. certutil -d /etc/httpd/alias/ -L -n Server-Cert | grep Serial
  2. ipa-getcert rekey -d /etc/httpd/alias -n Server-Cert
  3. ipa cert-show $SERIAL | grep Revoked

Actual behavior

# certutil -d /etc/httpd/alias/ -L -n Server-Cert | grep Serial
        Serial Number: 268369924 (0xfff0004)
# ipa-getcert rekey -d /etc/httpd/alias -n Server-Cert
Resubmitting "20180401114816" to "IPA".
# certutil -d /etc/httpd/alias/ -L -n Server-Cert | grep Serial
        Serial Number: 268369925 (0xfff0005)
# ipa cert-show 0xfff0004 | grep Revoked
  Revoked: False

Expected behavior

The previous certificate should get revoked automatically.

Version/Release/Distribution

freeipa-server-4.6.3-2.fc27.x86_64
freeipa-client-4.6.3-2.fc27.x86_64
package ipa-server is not installed
package ipa-client is not installed
389-ds-base-1.3.7.10-1.fc27.x86_64
pki-ca-10.5.6-2.fc27.noarch
krb5-server-1.15.2-7.fc27.x86_64
certmonger-0.79.5-2.fc27.x86_64

Additional info:

Just in case it makes a difference: my test system is composed of three replicas, two of them with CA and KRA.

I'm seeing one RPC request for the rekeying operation, [xmlserver] ... cert_request('MIIE...', profile_id='caIPAserviceCert', principal='HTTP/host.ipa.example@IPA.EXAMPLE', add=True, version='2.51'): SUCCESS

IPA keeps the old certificates in the multi-valued userCert attribute of the principal. For the HTTP server, it's krbprincipalname=HTTP/hostname@REALM,cn=services,cn=accounts,$SUFFIX. The old certs could be used to fix existing systems.

On a side note, the certificates are pretty large. It might be a good idea to replace the revoked certificates with a reference to Dogtag's tree, e.g. cn=268369925,ou=certificateRepository,ou=ca,o=ipaca for serial 0xff0004.

Edited 5 months ago by cheimes

ipa service-del correctly revokes all certificates, both the current one and all old ones.

The service_mod call is wrong. The cert_request plugin calls service_mod but the service plugin doesn't recognize that it should revoke the old certs.

(Pdb) w
  /usr/share/ipa/wsgi.py(57)application()
-> return api.Backend.wsgi_dispatch(environ, start_response)
  /usr/lib/python3.6/site-packages/ipaserver/rpcserver.py(265)__call__()
-> return self.route(environ, start_response)
  /usr/lib/python3.6/site-packages/ipaserver/rpcserver.py(277)route()
-> return app(environ, start_response)
  /usr/lib/python3.6/site-packages/ipaserver/rpcserver.py(693)__call__()
-> environ, start_response)
  /usr/lib/python3.6/site-packages/ipaserver/rpcserver.py(429)__call__()
-> response = self.wsgi_execute(environ)
  /usr/lib/python3.6/site-packages/ipaserver/rpcserver.py(370)wsgi_execute()
-> result = command(*args, **options)
  /usr/lib/python3.6/site-packages/ipalib/frontend.py(450)__call__()
-> return self.__do_call(*args, **options)
  /usr/lib/python3.6/site-packages/ipalib/frontend.py(478)__do_call()
-> ret = self.run(*args, **options)
  /usr/lib/python3.6/site-packages/ipalib/frontend.py(800)run()
-> return self.execute(*args, **options)
  /usr/lib/python3.6/site-packages/ipaserver/plugins/cert.py(894)execute()
-> if principal_type == SERVICE:
  /usr/lib/python3.6/site-packages/ipalib/frontend.py(450)__call__()
-> return self.__do_call(*args, **options)
  /usr/lib/python3.6/site-packages/ipalib/frontend.py(478)__do_call()
-> ret = self.run(*args, **options)
  /usr/lib/python3.6/site-packages/ipalib/frontend.py(800)run()
-> return self.execute(*args, **options)
  /usr/lib/python3.6/site-packages/ipaserver/plugins/baseldap.py(1422)execute()
-> *keys, **options)
> /usr/lib/python3.6/site-packages/ipaserver/plugins/service.py(698)pre_callback()
-> if 'usercertificate' in options and ca_is_enabled:
(Pdb) p 'usercertificate' in options
False
(Pdb) p options
{'addattr': ('usercertificate=MIIFo...',), 'rights': False, 'all': False, 'raw': False, 'version': '2.229', 'no_members': False}

host_mod is also affected. user_mod seems to ignore user certificates.

@ftweedal user_mod doesn't revoke old user certs. Is this the expected behavior?

4 months ago

Metadata Update from @rcritten:
- Issue assigned to rcritten
- Issue priority set to: critical
- Issue set to the milestone: FreeIPA 4.7

Researching this has exposed another bug in cert_request.

cert_request uses <object>_mod to set the usercertificate value. This does a full attribute replace, it is the equivalent of string a = b rather that list a += b.

The revocation code is already smart enough to revoke all the certs so if you do something like:

# getcert request ... -K test/$HOSTNAME
# ipa service-add-cert --certificate=<other cert. test/$HOSTNAME

You now have 2 valid certs in a service (why you'd want to is beside the point).

When you renew the cert them BOTH are revoked

# getcert resubmit ...

There is only one cert in ipa service-show because the other two have been revoked and/or removed from the entry (the revoke_cert cmd is already smart enough to only revoke certs issued by IPA).

Thinking more on this I'm not sure if this is a bug, feature, side-effect or expected.

The ONLY way that a second IPA-issued cert could get into the entry is if it is required for a DIFFERENT service/host/object and then added to another entry (which is how I reproduced this).

I don't know that this is a case we need to care about.

I think it would be a good idea to decompose the revocation and issuance behaviours.
i.e. it is undecidable in general whether a new certificate is intended to supersede some
existing certificate, such that revocation should be performed.

There are various heuristics you could use (e.g. "for cert with same key and same characteristics, which is close to expiry, assume it should be revoked). But even then, if it is close to expiry there is little benefit to revoking it. And the logic is fuzzy. And the heuristic are non-trivial.

I would rather see the behaviours decomposed and no implicit revocation. If cert-request revokes certificates it should be explicitly requested, and ideally the certificate(s) to revoke explicitly specified. But at that point it's simpler to just run cert-request and cert-revoke as separate commands.

Thoughts?

(Side-note, I am cool with {user,host,service}-del revoking certificates. (Although there should probably be a way to suppress that behaviour... but it's a question for a different ticket.)

Some other notes I put in the PR (https://github.com/freeipa/freeipa/pull/1915):


As I alluded in the ticket (https://pagure.io/freeipa/issue/7482) I think we should have a broader discussion about what is the correct revocation behaviour in cert-request.

There are three basic scenarios where cert-request will be revoked:

  1. requesting a certificate for some new purpose. the subject principal may already have certs for other purposes. existing certificates should not be revoked.
  2. renew an existing certificate, because the end of the validity period is near. therefore there is little benefit to revoking. furthermore, if there are multiple existing certificates, to decide which one is being replaced is non-trivial in ideal circumstances, and undecidable in general.
  3. rekey or reissue an existing certificate, for any reason, when the expiry is not near. the existing cert should be revoked. But again, it is not simple to determine which certificate is being replaced.

Proposal:

  • remove revocation behaviour from cert-request

    • revocation behaviour could be retained, but only activated if a speciifc argument is given e.g. cert-request CSR --principal PRINC --revoke ISSUER:SERIAL would revoke the certificate with ISSUER:SERIAL if (and only if) it appears in the subject principal's entry, and remove it from that entry.
  • enhance the IPA certmonger helper to supply the appropriate options or invoke ipa cert-revoke separately, to revoke the certificate being renewed. IIIRC the old certificate is provided in the certmonger helper's environment so this should be straightforward.

Edited 4 months ago by ftweedal
3 months ago

Metadata Update from @ftweedal:
- Issue close_status updated to: invalid

Login to comment on this ticket.

cancel