On 4.2.2017 16:40, Ben Lipton wrote:
On 01/12/2017 04:35 AM, Jan Cholasta wrote:
On 11.1.2017 00:38, Ben Lipton wrote:

On 01/10/2017 01:58 AM, Jan Cholasta wrote:
On 19.12.2016 21:59, Ben Lipton wrote:

On 12/15/2016 11:11 PM, Ben Lipton wrote:

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
development work for the CSR autogeneration project, and I
want to
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
for review can get reviewed and the ideas that have been
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
the design thread? By this I mean that currently there is a
(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
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
line, we'll need:
- An additional tool to sign a CSR given a CertificationRequestInfo
both types of key storage).
- A way to extract a SubjectPublicKeyInfo structure from a key
the ipa command (like [1] but we need it for both types of key
Since as far as I know there's no standard encoding for files
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

I didn't realize that python-cryptography knew about
SubjectPublicKeyInfo structures, but indeed this seems to be pretty

key = load_pem_private_key(key_bytes, None, default_backend())
pubkey_info = key.public_key().public_bytes(Encoding.DER,

Thanks for letting me know this functionality already existed.

I'm currently working on the step of signing the
CertificationRequestInfo and creating a CSR from it. I think I have it
working with pyasn1, but of course the "signature algorithm" for the CSR
needs to be specified and implemented within the code since I'm not
using a library that understands CSRs natively. The code I have
currently always produces CSRs with the sha256WithRSAEncryption
algorithm (DER-encode request info, SHA256, PKCS #1v1.5 padding, RSA
encryption), and the OID for that algorithm is hardcoded in the output
CSR. Is this ok or will we need more flexibility than that?

IMO it's OK for starters.

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.

This can be worked around by:

1. Generating a key + temporary certificate:

    n=$(head -c 40 /dev/urandom | base32)
    certutil -S -n $n -s CN=$n -x -t ,,

2. Extracting the public key from the certificate:

    certutil -L -n $n -a >temp.crt
    (extract the public key using python-cryptography)

3. Deleting the temporary certificate:

    certutil -D -n $n

4. Importing the newly issued certificate:

    certutil -A -n $n -t ,, -a <new.crt

Oof, thanks, I'm not sure I would have been able to come up with that.
Can you generate a key without a temporary certificate if you use the
NSS API, or does their model require every key to belong to a cert?

I'm pretty sure it's possible, but it certainly won't be as simple as
this. I gave up after a few hours of digging into NSS source code and
not being able to figure out how.

As for encoding, the obvious choice is DER. It does not really
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
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
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.

You can close the old one.

Just to make sure we are on the same page, you want this PR to be
merged before submitting additional PRs built on top of it?

Yes, I would like to merge this one to have as a starting point if
you're comfortable with it: https://github.com/freeipa/freeipa/pull/337.
I just did a force push to clean up the history, but the final diff
should be the same as it was before.


I would probably just implement the adapters within the
cert_build/cert_request client code unless you think having
tools is valuable. I suppose certmonger is going to need these
too, but I don't know how well sharing code between them is
going to

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:

Good idea :-)

- Automation for the full process from getting CSR data to
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
the modified cert-request. (Not that the current solution is so
what with the copying of options from cert_request and certreq.)
If I
remember correctly, I was uncertain how to implement parameters
required/invalid based on other parameters: the current
takes a signed CSR (required), a principal (required), and a
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)

IMO profile ID should default to caIPAserviceCert on the client as

I originally had it doing so, but changed it to a required option
based on feedback in this email:

"In general use I think that 'caIPAserviceCert' is unlikely to be
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
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
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?
Just wanted to call attention to this question. The code that's
currently problematic is here:

(will pass None when in fact the argument default should be used).


Other prototypes and design ideas that aren't ready for

- 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:

Nice! As I said above, this could really make implementing the
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
on the certutil/openssl tools. However, I don't think any of the
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
that certmonger generates, calls out to IPA for profile-specific
and returns an updated CertificationRequestInfo built from the
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

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].


Anyway, the ultimate goal is to move the csrgen code to the
which means everything the helper will have to do is call a
over RPC.

- Tool to convert an XER-encoded cert extension to DER, given the
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
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
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.

It took me some experimentation to get this to work, but the solution
with asn1c is actually quite simple because the tool automatically
provides a sample C file that converts between different formats. So,
this very basic shell script is able to do the conversion:

$ cat ExtKeyUsage.xer

$ cat KeyUsage.asn1

KeyUsage ::= BIT STRING {
     digitalSignature        (0),
     nonRepudiation          (1),  -- recent editions of X.509 have
                                -- renamed this bit to
     keyEncipherment         (2),
     dataEncipherment        (3),
     keyAgreement            (4),
     keyCertSign             (5),
     cRLSign                 (6),
     encipherOnly            (7),
     decipherOnly            (8) }

ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId



$ ./xer2der.sh KeyUsage.asn1 ExtKeyUsageSyntax ExtKeyUsage.xer
2>/dev/null | xxd
00000000: 3014 0608 2b06 0105 0507 0302 0608 2b06 0...+.........+.
00000010: 0105 0507 0304                           ......

So far I don't have a working example using libtasn1. I have something
close to it, but it's hacky, as the libtasn1 API is pretty limited,
and I didn't have time to work on it in the last few weeks.

I got it working, needs just a little polishing. It's still ugly hacky

So: currently on my to do list are the certmonger helper and the
XER->DER conversion tool. Do you have any comments about these
and is there anything else I can do to wrap up the project





Thank you for the review! I just created
https://github.com/freeipa/freeipa/pull/433 and
https://github.com/freeipa/freeipa/pull/434 for the two follow-up
branches I had pending (and updated with ideas from this thread and the
previous PR's thread). I'm still working on converting the API to
consuming SubjectPublicKeyInfo structures and producing
CertificationRequestInfo ones - I have the OpenSSL flow working, but am
still missing a step for the NSS flow. Specifically, after step 2 of the
4 you suggested above, I need to use NSS to use the private key in the
db to sign the SubjectPublicKeyInfo before I can use python-cryptography
to make it into a CSR like I'm doing with OpenSSL. I'm sure this is not
very hard, but I haven't quite figured it out yet.

Sigh, NSS does not have a generic signing tool (cmsutil and signtool are not generic enough) and python-nss does not have a signing API. I got this far:

    from nss import nss


    nss.set_password_callback(lambda slot, retry, password: password)
    slot = nss.get_internal_key_slot()
    slot.authenticate(False, db_password)

    cert = nss.find_cert_from_nickname(nickname)
    key = nss.find_key_by_any_cert(cert)

Unfortunately this means we will have to call C code. IMO it would be best to drop support for NSS for the time being and add it back when we know exactly what C code to call.

Jan Cholasta

Manage your subscription for the Freeipa-devel mailing list:
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to