Closed Bug 341371 Opened 18 years ago Closed 17 years ago

certutil lacks a way to request a certificate with an existing key

Categories

(NSS :: Tools, defect, P3)

3.12
defect

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: rcrit, Assigned: neil.williams)

References

Details

(Whiteboard: PKIX)

Attachments

(7 files, 3 obsolete files)

certutil lacks a way to request a certificate with an existing key. The -R flag always generates a new key with the CSR.

For certificate renewal purposes it would be helpful to generate a CSR using an existing key.
Priority: -- → P3
Do we validate the existing key? Or we just trust? Do we have any function to validate keys? 
There is no way to verify a key per se - you need an external source of trust. Usually a public key is verified as part of cert verification. However, when generating a CSR from an existing key, we wouldn't need to verify the key, since the user explicitly specified that he wants to create that CSR with the specific public key (presumably by specifying the issuer/serial number of the older cert).
PKCS #10 says that private key is required for sigining the certification request.
What could be the format of the input pvt key,so that we can recover it easily? 
Assignee: nobody → biswatosh.chakraborty
Biswatosh,

For this RFE, you can assume that both the certificate (which contains the public key) and the private key are already available and stored in the NSS databases, cert8.db/key3.db, or in another PKCS#11 token . You don't need to worry about importing any certs or keys.

The RFE is useful for users of products, typically servers, which have previously obtained a certificate and private key, but for which the certificate expired. These users have since lost the original Certificate Signing Request that they used to obtain their certificate. They want to get a new certificate with the same public key in it. That certificate wouldn't be useful to them if they had lost the private key, so you can assume that they have the private key. As it turns out, the private key is also required to create a new CSR for proof-of-possession purposes.

So, the main job you have to do are :

1. locate the existing public/private keys

a. locate the right certificate, then extract the public key
b. find the private key that matches the public key or cert

2. generate a new CSR using the existing keypair and information from the certutil command-line similar to certutil -R, except it wouldn't need the information pertaining to key generation

The trickiest part of those is step 1a, locating the right certificate and public key.
The easiest solution would be to call PK11_FindCertFromNickname .
But this is probably inappropriate because :
a) there may be multiple certs with the same subject, ie same nickname 
PK11_FindCertFromNickname will only return the newest cert
b) these multiple certs may have different public key values, or even key types

You need to precisely identify the cert and key.

One approach is to call PK11_FindCertsFromNickname . Note the plural "certs". It will return you a list of cert. If there is only one, you can just use it.
If there is more than one, you can extract the public key value from each cert, and see if they are the same. If so, any of the certs will do. If not, you would require additional information from the command-line to choose the right cert, probably an issuer and serial number.
(In reply to comment #4)

Thanx Julien for your suggestions. I plan to change certutil code to enable the following:

Firstly, as usual, certutil -R -s "cn=whatever" -d "database" -o "out.cer" will work as before.

Secondly, I add two new options, -9 and -I where -9 will mean "UseOldCert" and -I is to supply password for the database.  
Now, if certutil -R -n nickname -9 -I -s ... is used, PK11_FindCertsfromNickName() will be called to get the list of certs. The public keys of the certs fetched from the certlist will be compared(by memcmp-ing cert->derPublicKey.data of the certs),and if they are all same, then that is the pub key we need.
If the keys are different, we will prompt the user to supply additional informations like serial number and issuer name and then parse the same certlist 
to get the cert which matches these infos. If we get it, then that is the pub key we require and we identify the cert from which we had it.
And,then simply call PK11_FindKeybyAnyCert() by passing the identified cert.
Now we have the pvt and pub key and then we pass these to the CertReq() function, the way it is passed when we just do a certutil -R -d without -I and -9 options.

I have written the basic code to do this and if you say this is fine, I will complete this and give it for review after my unit test. 

 
 
Biswatosh,  

Your work on bug 291383 should also be helpful with this bug.
You've learned how to find keys by keyID.
It would be useful to be able to generate a new CSR using an 
existing key that is specified by keyID.  
(I could surely use that feature right now if it existed. :)

Doesn't certutil already have an option for specifying password
on the command line?  If so, we should reuse that option and not
attempt to allocate another option to it.
You can have a password file with certutil. I don't think you can pass one in via a command-line option though (ala -w with most other commands). To pass it via a file specify: -f pwfile
This attachment is to give the idea of the actual patch to be attached soon for review.
It works as planned. With this, one can generate a CertReq without having to generate new keys. So, either the user supplies (1) nickname and optionally issuername and/or serial number of the cert OR (2) the user supplies KEYID.

Options already in use will be reused. For example,
certutil -R -n "A12345FC..." -l will interpret the nickname as the KeyId and based on that find the pvt key and pub key. 
certutil -R -n "Ramesh" will search through all the certs with this nickname "Ramesh" and if found, will choose the first cert,based on which it will find the pub key and pvt key in the database and then use that to generate a CertReq.
If it supplies serial no or/and issuer name, then among all certs with nickname "Ramesh", it will try to see the certs which have the given serial no and issuer name. It will stop after the first match and find the pvt and pub keys. So, if a user supplies just nickname, he should know that it could one of many. To further reduce the scope, it can give the other two options OR of course by just giving the KeyId and with neither of these three options(nickname,serial num,issuername).
This patch attached has now to be made complete, for example seeing that no mem leak exists. After that, it will be given for review.

But, if anybody could give just a glance on the attachment and point out any serious mistake/s or has some suggestion/s, it will be very helpful.
This attachment is to give the idea of the actual patch to be attached soon for review.
It works as planned. With this, one can generate a CertReq without having to generate new keys. So, either the user supplies (1) nickname and optionally issuername and/or serial number of the cert OR (2) the user supplies KEYID.

Options already in use will be reused. For example,
certutil -R -n "A12345FC..." -l will interpret the nickname as the KeyId and based on that find the pvt key and pub key. 
certutil -R -n "Ramesh" will search through all the certs with this nickname "Ramesh" and if found, will choose the first cert,based on which it will find the pub key and pvt key in the database and then use that to generate a CertReq.
If it supplies serial no or/and issuer name, then among all certs with nickname "Ramesh", it will try to see the certs which have the given serial no and issuer name. It will stop after the first match and find the pvt and pub keys. So, if a user supplies just nickname, he should know that it could one of many. To further reduce the scope, it can give the other two options OR of course by just giving the KeyId and with neither of these three options(nickname,serial num,issuername).
This patch attached has now to be made complete, for example seeing that no mem leak exists. After that, it will be given for review.

But, if anybody could give just a glance on the attachment and point out any serious mistake/s or has some suggestion/s, it will be very helpful.
This attachment is to give the idea of the actual patch to be attached soon for review.
It works as planned. With this, one can generate a CertReq without having to generate new keys. So, either the user supplies (1) nickname and optionally issuername and/or serial number of the cert OR (2) the user supplies KEYID.

Options already in use will be reused. For example,
certutil -R -n "A12345FC..." -l will interpret the nickname as the KeyId and based on that find the pvt key and pub key. 
certutil -R -n "Ramesh" will search through all the certs with this nickname "Ramesh" and if found, will choose the first cert,based on which it will find the pub key and pvt key in the database and then use that to generate a CertReq.
If it supplies serial no or/and issuer name, then among all certs with nickname "Ramesh", it will try to see the certs which have the given serial no and issuer name. It will stop after the first match and find the pvt and pub keys. So, if a user supplies just nickname, he should know that it could one of many. To further reduce the scope, it can give the other two options OR of course by just giving the KeyId and with neither of these three options(nickname,serial num,issuername).
This patch attached has now to be made complete, for example seeing that no mem leak exists. After that, it will be given for review.

But, if anybody could give just a glance on the attachment and point out any serious mistake/s or has some suggestion/s, it will be very helpful.
Attachment #252331 - Attachment is obsolete: true
Attachment #252332 - Attachment is obsolete: true
Pls ignore Comment #9 and Comment #10 . It is the same as Comment #8 and that is
why, I  made the attachments in comments 9 and 10 obsolete. It happened because of my silly mistake. Very sorry for that! After having uploaded patch for Comment #8 , I used the "Back" of the browser just to see, to whom all the mails were sent and surprisingly, that seemed to have uploaded the same comment once over. I did it again and saw it repeated. Pls ignore. Thanks  
Comment on attachment 252330 [details]
Not for Review. Just to show the status.

This is not a patch.
Attachment #252330 - Attachment is patch: false
Version: 3.11.1 → 3.12
Target Milestone: --- → 3.12
This patch can create a CertReq without having to generate keys. It can take CKA_ID or a nickname and optionally issuername and serial number. This is an improvement over the previous attachment in that it itself is a ran and tested code.  The previous one was just to give the plan of the code to be written.
This tries to extract CKA_ID of a public key in a different way. The earlier patch(254042) tried first to get the modulus of a rsa key etc and then called MakeIDFromPubKey() by supplying the modulus to it.
This patch creates a new function PK11_GetKeyIDFromPublicKey() in the same style
as PK11_GetKeyIDFromPrivateKey() and calls that to get the CKA_ID. It has to be discussed which way is better.
(More on comment #14)
In the attachment in Comment #14, a function FindKeybyID() is being
called within the function  FindKeysbyKeyID(). This function(FindKeybyID())
is currently not a part of the NSS library. It has rather been proposed
to solve https://bugzilla.mozilla.org/show_bug.cgi?id=291383 .
This function and FindPubKeybyID() are quite similar in that the former
extracts pvt key and the latter extracts pub key and their logics are
quite similar. So, the present patch shall work if the latest patch proposed 
for bug id 291383 gets checked in. I wont like to call that a dependency
because in principle, this bug is not really dependent on bug id 291383. There
can be alternate ways of doing it.
An added feature to the patch in Comment #14 :

This tries to enable finding the cert by giving Issuer Alternative Name in
addition to nickname,issuername,serial number. The earlier patch could not 
handle IssuerAltName but this proposed solution can.

However, it seems certutil cannot add an extension with an AltIssuerName.
See the code in the function AddExtensions() in certutil.c.
There, it calls CERT_AddExtension() with SEC_OID_X509_SUBJECT_ALT_NAME towards
the end of the code but nowwhere with SEC_OID_X509_ISSUER_ALT_NAME.
So, a certutil command with options -7 or -8 adds SubAltName and not
IssuerAltName. Hence, the testing of my proposed solution needs this presently
absent feature also.
Anyways,I am attaching a code which is not a patch and has some things to be done
but shows my idea of how to verify whether a certificate has a given issuer
alternative name. 

The earlier patch had a function called FindCertbyAttributes(). This attachment
has rewritten the same function by making an extra argument to it, to enable passing IssuerAltName as well and therefore a small change in the code to deal with the new parameter is also introduced.
Comparison of both can immediately tell the difference.
This basically combines patches in Comment #14 and Comment #16.
It contains some functions which were added/changed in bug 291383.
These have been given here because this solution assumes the existence of
the changes proposed in Bug 291383. That is one of the reasons why I am 
not giving this for review. So, this patch by itself is a self-contained
one.
Whiteboard: PKIX
This patch implements key reuse for -R and -S in a rather simple way, allowing the user to specify the nickname of a cert whose key pair should be used for a new CSR or cert. Biswatosh's solution is a deeper implementation. I haven't perused it yet.
Assignee: biswatosh.chakraborty → neil.williams
Status: NEW → ASSIGNED
Attachment #266967 - Flags: review?(nelson)
Comment on attachment 266967 [details] [diff] [review]
get the private from a cert by nickname

When bug 291383 is fixed this fix should use the private key IDing method as that patch. Perhaps this should wait for it?
Comment on attachment 266967 [details] [diff] [review]
get the private from a cert by nickname

I sent review comments to Neil.
Attachment #266967 - Flags: review?(nelson) → review-
Attachment #266967 - Attachment is obsolete: true
Attachment #268281 - Flags: review?(nelson)
Comment on attachment 268281 [details] [diff] [review]
addresses Nelson's comments

r=nelson
Attachment #268281 - Flags: review?(nelson) → review+
/cvsroot/mozilla/security/nss/cmd/certutil/certutil.c,v  <--  certutil.c
new revision: 1.111; previous revision: 1.110
done
Status: ASSIGNED → RESOLVED
Closed: 17 years ago
Resolution: --- → FIXED
The fix for this bug only works for RSA key types.  
It does not work for DSA key types, or any other key type than RSA.
Patch forthcoming.
Status: RESOLVED → REOPENED
Resolution: FIXED → ---
This patch fixes the key type problem by always taking the key type
from the found private key.
It also corrects a problem where certutil was incorrectly insisting
that the subject name MUST have a common name. 

Neil & Alexei, please review.
Attachment #275278 - Flags: superreview?(alexei.volkov.bugs)
Attachment #275278 - Flags: review?
Attachment #275278 - Flags: review? → review?(neil.williams)
This was the test command I used:

certutil -R -k "DSA self signed" -a -s "L=Gaithersburg,O=Test Certificates,C=US"
Attachment #275278 - Flags: superreview?(alexei.volkov.bugs) → superreview+
Comment on attachment 275278 [details] [diff] [review]
fix key type and subject name problems

Checking in certutil.c; new revision: 1.115; previous revision: 1.114
Attachment #275278 - Flags: review?(neil.williams)
Status: REOPENED → RESOLVED
Closed: 17 years ago17 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: