I have a scenario in which I would like to automate the deployment of client certificates generated by an issuer I control. The approach I am considering is given below, and I would appreciate feedback as to risks involved (or if this is more complex than necessary). The communications described would be SOAP style WCF over HTTPS.

A registration key is generated at the server.

The registration key is shared out of band with a person who will perform the registration.

The user uses the registration key to initiate registration.

The client system registering creates an in memory key pair

The client system transmits the registration info, including the public key for the in memory key pair, and the registration code.

The server validates the registration code, creates a client certificate and corresponding private key and an in memory PKCS12.

The server further encrypts the PKCS12 with the public key provided by the client.

The client receives the server response, decrypts the returned certificate data, and imports it into a local key store.

3 Answers
3

Instead of generating a first key-pair in your client (which you seem to discard at after this procedure) and generating another key-pair in the server to produce the certificate, you could:

generate a single key-pair in the client,

turn its public key into a certification request,

send it via HTTPS with the registration info to your issuer service,

have the service issue the certificate and send it back,

the client associates the certificate with the private key.

All of this can be done directly within a browser, for example, but can also be done by other clients, such as your custom SOAP-based client. It has the advantage that the private key never leaves the party meant to keep hold of it: the client doesn't even need to trust the issuer service not to have kept a copy.

Provided that you trust the HTTPS connection to be certain that the registration info was indeed sent with this particular certification request, your initial verification mechanism will be fine.

EDIT:

Following comments, it seems that you don't want your private keys to be kept for escrow on your issuing server anyway. In this case, there's no point taking the risk of transmitting the private key at all. You're not gaining anything by generating the certificate key-pair on the server; if anything, you're increasing the risk (albeit limited by the fact you're transmitting that private key over HTTPS anyway).

What you really want to make sure of is that the public key used for the certificate and the registration key shared out of bands belong to the same person. From that point of view, if they give your their public key, or if you generate it and give it back to them (with the private key) is the same. Transmitting the private key one way or another in this scheme is just unnecessary.

All you need to do is to get the public key from the request/application (in the sense that the user requests/applies for the cert), check that it came with the right registration secret, and issue the cert. You can get this public key from a CSR or just as a plain public key if you want. (The details of what the applicant may have put in the CSR are barely relevant, any good CA should discard it and only put what it has verified out of bands into the cert anyway.)

If the client has verified the HTTPS connection to your server is configured properly: strong-enough cipher suites, turning off TLS compression, and proper certificate verification, you should be guaranteed that the secret registration info and the public key came together.

Whether or not to trust the HTTPS connection is much of the key to my concerns. Assuming HTTPS is required, with no redirect fro the corresponding HTTP URL, when would I not trust the connection?
–
cmsjrSep 26 '12 at 23:20

As a service, you can never know for sure that your clients have checked their certificates properly to avoid MITM attacks (unless they're using client-certs, but you're at the stage before that here). Checking this solely the responsibility of the client anyway. Make sure that your clients (and their users) verify the certificate of your server properly.
–
BrunoSep 26 '12 at 23:30

I've decided to go with client side certificate generation. Originally I had thought that there would be a certain non-repudiation benefit in being able to ensure I issued a client certificate, but on further consideration, if I am not going to cache the private key, then providing the certificate is really no different from any other highjacked credential. Thanks much for your input. Many thanks for you insights.
–
cmsjrSep 29 '12 at 9:56

@cmsjr, you should still generate the certificate itself on the server, it's the key-pair (and certificate request) that should be done on the client side.
–
BrunoSep 29 '12 at 12:08

And thanks, again. The way I had it structured the key pair was being created at the same time as the certificate, I split it out so that now the client generates the key pair, sends over public key with request, and the server creates and returns certificate. Huge help.
–
cmsjrSep 29 '12 at 21:57

This is an accepted method. For example, SecureWorks issues client certs over SSL following a registration process. The risks profile is mostly as follows:

Ensuring registration can't be performed by someone other than the intended party; this is generic with other registration processes, and can be the largest risk to address.

The transfer of the key via HTTPS is not particularly risky.

Trusting the user to correctly handle their key once they get it. Nothing you can do about this no matter how you get the key to them.

Ensuring protection of client keys on your end. Are you going to escrow them so people can re-download them? Or wipe them as soon as the client has them and generate a new one in the future as necessary? The traditional "generate key on the client" preference largely has to do with well-founded distrust of the ability of other systems to forget the keys if they ever knew them.

Thanks for the reply. I was planning on doing the certificate generation in memory, and only storing the resulting thumbprint after the fact. Is that reasonable?
–
cmsjrSep 26 '12 at 22:41

@cmsjr, why go through all that trouble if you're not keeping the private key with the issuer (for subsequent re-download, as gowenfawr suggests)?
–
BrunoSep 26 '12 at 22:51

In subsequent authentications I want to ensure the certificate is one I issued. If I give that part up, I agree with you that client side generation probably makes the most sense.
–
cmsjrSep 26 '12 at 23:11

@cmsjr, in both cases, you're the one issuing the certificate, no difference there. You step only differs in that you want to transfer the private key, which you wouldn't need to do at all otherwise. Since you're giving back the cert to the party that gave you its registration info, whether you "link" this reg. info to a public key you generate or the remote party generate (to turn it overall into a cert) doesn't really matter.
–
BrunoSep 26 '12 at 23:27

The procedure looks fine but you have to decide of a format for the encryption of the PKCS#12 file with the asymmetric key which was generated at step 4. This is not as easy as it seems and you'd better stick to a standard format.

At that point, notice that PKCS#12 has an inherent ability to do symmetric encryption, normally with a "password" but the password can be long and random. Your procedure can be simplified if you use the "registration key" as the password to encrypt the PKCS#12 file. This would avoid having to generate an in-memory key pair on the client side.

Actually, since the in-memory key pair generated by the client is authenticated only by virtue of being sent in the HTTPS tunnel along with the registration code, you are already assuming that HTTPS offers sufficient security and prevents an attacker from substituting his own key pair at that point. You might as well go to the end of that logic and simply trust the HTTPS tunnel: just send the certificate and private key as is. Packing them as a PKCS#12 file, encrypted with the registration code (since that code is also assumed to be secret enough), may ease integration (e.g. the user might obtain the PKCS#12 as a file, and import it in his OS "manually").