[Freeipa-devel] CSR autogeneration next steps
Ben Lipton
blipton at redhat.com
Fri Dec 16 04:11:05 UTC 2016
On 12/12/2016 03:52 AM, Jan Cholasta wrote:
> On 5.12.2016 16:48, Ben Lipton wrote:
>> Hi Jan, thanks for the comments.
>>
>>
>> On 12/05/2016 04:25 AM, Jan Cholasta wrote:
>>> Hi Ben,
>>>
>>> On 3.11.2016 00:12, Ben Lipton wrote:
>>>> Hi everybody,
>>>>
>>>> Soon I'm going to have to reduce the amount of time I spend on new
>>>> development work for the CSR autogeneration project, and I want to
>>>> leave
>>>> the project in as organized a state as possible. So, I'm taking
>>>> inventory of the work I've done in order to make sure that what's
>>>> ready
>>>> for review can get reviewed and the ideas that have been discussed get
>>>> prototyped or at least recorded so they won't be forgotten.
>>>
>>> Thanks, I have some questions and comments, see below.
>>>
>>>>
>>>> Code that's ready for review (I will continue to put in as much
>>>> time as
>>>> needed to help get these ready for submission):
>>>>
>>>> - Current PR: https://github.com/freeipa/freeipa/pull/10
>>>
>>> How hard would it be to update the PR to use the "new" interface from
>>> the design thread? By this I mean that currently there is a command
>>> (cert_get_requestdata), which creates a CSR from profile id +
>>> principal + helper, but in the design we discussed a command which
>>> creates a CertificationRequestInfo from profile id + principal +
>>> public key.
>>>
>>> Internally it could use the OpenSSL helper, no need to implement the
>>> full "new" design. With your build_requestinfo.c code below it looks
>>> like it should be pretty straightforward.
>>
>> This is probably doable with the cffi, but I'm concerned about
>> usability. A user can run the current command to get a (reusable)
>> script, and run the script to get a CSR. It works with keys in both PEM
>> files and NSS databases already. If we change to outputting a
>> CertificationRequestInfo, in order to make this usable on the command
>> line, we'll need:
>> - An additional tool to sign a CSR given a CertificationRequestInfo (for
>> both types of key storage).
>> - A way to extract a SubjectPublicKeyInfo structure from a key within
>> the ipa command (like [1] but we need it for both types of key storage)
>> Since as far as I know there's no standard encoding for files containing
>> only a CertificationRequestInfo or a SubjectPublicKeyInfo, we'll be
>> writing and distributing these ourselves. I think that's where most of
>> the extra work will come in.
>
> For PEM files, this is easily doable using python-cryptography (to
> extract SubjectPublicKeyInfo and sign CertificationRequestInfo) and
> PyASN1 (to create a CSR from the CertificationRequestInfo and the
> signature).
I didn't realize that python-cryptography knew about
SubjectPublicKeyInfo structures, but indeed this seems to be pretty
straightforward:
key = load_pem_private_key(key_bytes, None, default_backend())
pubkey_info = key.public_key().public_bytes(Encoding.DER,
PublicFormat.SubjectPublicKeyInfo)
Thanks for letting me know this functionality already existed.
>
> For NSS databases, this will be trickier and will require calling C
> functions, as neither certutil nor python-nss provide a way to a)
> address existing keys in the database by key ID b) get
> SubjectPublicKeyInfo for a given key.
>
> As for encoding, the obvious choice is DER. It does not really matter
> there is no standard file format, as we won't be transferring these as
> files anyway.
Agreed. I just meant there aren't tools already because this isn't a
type of file one often needs to process.
>
>>
>> Would it be ok to stick with the current design in this PR? I'd feel
>> much better if we could get the basic functionality into the repo and
>> then iterate on it rather than changing the plan at this point. I can
>> create a separate PR to change cert_get_requestdata to this new
>> interface and at the same time add the necessary adapters (bullet points
>> above) to make it user-friendly.
>
> Works for me.
Updated the PR to fix conflicts with master. Had some trouble with CI
but creating a new PR with the same commits fixed it
(https://github.com/freeipa/freeipa/pull/337). Not sure if it's fixed
permanently, so I guess I'll just keep the two PRs synchronized now, or
we could close the old one.
>
>>
>> I would probably just implement the adapters within the
>> cert_build/cert_request client code unless you think having standalone
>> tools is valuable. I suppose certmonger is going to need these features
>> too, but I don't know how well sharing code between them is going to
>> work.
>
> cert-request is exactly the place where it should be :-) I wouldn't
> bother with certmonger until we have a server-side csrgen.
>
>>>
>>>>
>>>> - Allow some fields to be specified by the user at creation time:
>>>> https://github.com/LiptonB/freeipa/commits/local-user-data
>>>
>>> Good idea :-)
>>>
>>>>
>>>> - Automation for the full process from getting CSR data to requesting
>>>> cert: https://github.com/LiptonB/freeipa/commits/local-cert-build
>>>
>>> LGTM, although I would prefer if this was a client-side extension of
>>> cert-request rather than a completely new command.
>>
>> I did try that at first, but I struggled to figure out the interface for
>> the modified cert-request. (Not that the current solution is so great,
>> what with the copying of options from cert_request and certreq.) If I
>> remember correctly, I was uncertain how to implement parameters that are
>> required/invalid based on other parameters: the current cert-request
>> takes a signed CSR (required), a principal (required), and a profile ID;
>> the new cert-request (what I implemented as cert-build) takes a
>> principal (required), a profile ID (required), and a key location
>> (required). I can't remember if that was the only problem, but I'll try
>> again to merge the commands and get back to you.
>
> To make the CSR argument optional on the client, you can do this:
>
> def get_options(self):
> for option in super(cert_request, self).get_options():
> if option.name == 'csr':
> option = option.clone(required=False)
> yield
>
> IMO profile ID should default to caIPAserviceCert on the client as well.
I originally had it doing so, but changed it to a required option based
on feedback in this email:
https://www.redhat.com/archives/freeipa-devel/2016-August/msg00021.html:
"In general use I think that 'caIPAserviceCert' is unlikely to be used a
majory of the time, and it is a new command so there are no
compatibility issues; therefore why not make the profile option
mandatory?" I guess since we're talking about cert-request now, the
compatibility issues are back.
https://github.com/LiptonB/freeipa/commits/local-cert-build has now been
updated to change the cert_request command rather than adding a new
command. It seems to work now (thanks for the advice on making the
argument optional), the only thing I'm having trouble with is the
default for the profile_id argument. Previously, the default was applied
by this code in cert_request.execute:
profile_id = kw.get('profile_id', self.Backend.ra.DEFAULT_PROFILE)
But now, in the client, I need the default to pass to
cert_get_requestdata if no profile is specified. I'm not sure I can
access backends from the client to get it the same way the server code
does. Should I just import ipapython/dogtag.py and use the
DEFAULT_PROFILE set in there? Is there a way I can give the option a
default that will be seen in both the server and the client?
>
>>>
>>>>
>>>> Other prototypes and design ideas that aren't ready for submission
>>>> yet:
>>>>
>>>> - Utility written in C to build a CertificationRequestInfo from a
>>>> SubjectPublicKeyInfo and an openssl-style config file. The purpose of
>>>> this is to take a config that my code already knows how to
>>>> generate, and
>>>> put it in a form that certmonger can use. This is nearly done and
>>>> available at:
>>>> https://github.com/LiptonB/freeipa-prototypes/blob/master/build_requestinfo.c
>>>>
>>>>
>>>
>>> Nice! As I said above, this could really make implementing the "new"
>>> csrgen interface simple.
>>>
>>>>
>>>>
>>>> - Ideally it should be possible to use this tool to reimplement the
>>>> full
>>>> cert-request automation (local-cert-build branch) without a dependency
>>>> on the certutil/openssl tools. However, I don't think any of the
>>>> python
>>>> crypto libraries have bindings for the functions that deal with
>>>> CertificationRequestInfo objects, so I don't think I can do this in
>>>> the
>>>> short term.
>>>
>>> You can use python-cffi to write your own minimal bindings. It's
>>> fairly straightforward, take a look at FreeIPA commit 500ee7e2 for an
>>> example of how to port C code to Python with python-cffi.
>>
>> Thank you for the example. I will take a look.
>>>
>>>>
>>>> - Certmonger "helper" program that takes in the
>>>> CertificationRequestInfo
>>>> that certmonger generates, calls out to IPA for profile-specific data,
>>>> and returns an updated CertificationRequestInfo built from the data.
>>>> Certmonger doesn't currently support this type of helper, but (if I
>>>> understood correctly) this is the architecture Nalin believed would be
>>>> simplest to fit in. This is not done yet, but I intend to complete it
>>>> soon - it shouldn't require much code beyond what's in
>>>> build_requestinfo.c.
>>>
>>> To me this sounds like it should be a new operation of the current
>>> helper rather than a completely new helper.
>>
>> Maybe so. I certainly wouldn't call this a finished design, I just
>> wanted to have some kind of proof of concept for how the certmonger
>> integration could work. For what it's worth, that prototype is now
>> available at [2].
>
> OK.
>
>>>
>>> Anyway, the ultimate goal is to move the csrgen code to the server,
>>> which means everything the helper will have to do is call a command
>>> over RPC.
>>>
>>>>
>>>> - Tool to convert an XER-encoded cert extension to DER, given the
>>>> ASN.1
>>>> description of the extension. This would unblock Jan Cholasta's
>>>> idea of
>>>> using XSLT for templates rather than text-based formatting. I
>>>> should be
>>>> able to implement the conversion tool, but it may be a while before I
>>>> have time to demo the full XSLT idea.
>>>
>>> Was there any progress on this?
>>
>> I have started working on implementing it with asn1c, and I'm already
>> seeing some of the inconvenience (security issues aside) of building on
>> the server. Libtasn1 seems like a much better model, but doesn't seem to
>> have XER support. Anyway, don't quite have results here yet but I think
>> I should have the XER->DER demo with asn1c ready in a week or two.
>
> Implementing XER codec on top of libtasn1 shouldn't be too hard; I
> have a WIP which I will post soon.
>
>>>
>>>>
>>>> So: currently on my to do list are the certmonger helper and the
>>>> XER->DER conversion tool. Do you have any comments about these plans,
>>>> and is there anything else I can do to wrap up the project neatly?
>>>>
>>>> Thanks,
>>>> Ben
>>>>
>>>
>>> Honza
>>>
>> [1] https://github.com/LiptonB/freeipa-prototypes/blob/master/key2spki.c
>> [2]
>> https://github.com/LiptonB/freeipa-prototypes/blob/master/cm_ipa_csrgen.c
>>
>
More information about the Freeipa-devel
mailing list