Projects/Certificate authorization pluggable interface
The PKINIT kdcpreauth module currently requires that client certificates contain a SAN (Subject Alternative Name) field containing either a Kerberos principal or a Microsoft UPN. In some deployments, certificates are issued from a third-party authority which does not support adding these fields.
We will create a new pluggable interface called "certauth" (name subject to change) to determine whether a certificate is authorized to authenticate to a principal. A certauth module can be implemented in the same shared object as a KDB module, and can use the krb5_context pointer to get at the DB handle; alternatively, it can be standalone. If it is standalone, it can either be aware of the KDB interface or be agnostic to it.
In addition to the usual initialization and finalization methods, a certauth module will have one method (name TBD). This method has the following inputs:
- A raw octet string containing the raw ASN.1 encoding of the certificate. (Passing a decoded representation of the certificate would create an interface dependency on OpenSSL.)
- The requested client principal name (probably the post-canonicalized name in the DB entry, not the name in the request).
- The client principal DB entry. A module which is agnostic to the KDB interface will ignore this pointer, and will just look at the client principal name.
It will have the following outputs:
- An authorization status: "yes", "no", or "pass". Typical modules will answer "yes" or "pass", but a module can answer "no" if it wants to implement a restrictive policy on top of all other modules.
- An optional list of auth indicators to add to the ticket based on the contents of the certificate. Typical modules will not supply any auth indicators.
The PKINIT kdcpreauth module implementation will be the consumer of this pluggable interface. It will consult all certauth modules on the certificate and requested client principal, stopping if any of them answer "no". The certificate is considered authorized if at least one module answers "yes" and none of the modules answer "no". All auth indicators returned by any module (even the ones that answered "pass") are added to the ticket.
The PKINIT kdcpreauth module will provide the following built-in modules:
- san: A module implementing the current Subject Alternative Name matching logic.
- eku: A module implementing the current extended key usage checking logic.
- dbmatch: A module which looks up a string attribute on the client DB entry (name TBD) and matches it against the certificate using the pkinit_matching.c functions (which are currently only used by the clpreauth module to select a client certificate).
- In the current design, the builtin modules will each have to re-parse the certificate. Can we somehow avoid that extra work without using an OpenSSL type in the pluggable interface?
Lower effort options
Implementing the functionality of the second builtin module (matching the certificate against a string attribute) would significantly increase functionality, and would not get in the way of implementing the pluggable interface later.