Hi, I'm back from vacation (and of course something went wrong in production during my absence...)
As far as I can see we have had a race condition between two certificate issuance operations. Setting: 1 User A requested a certificate via a "Basic Request" 2 User B requested a certificate via a "Server Request" 3 both requests were approved 4 Certificate A was issued 5 Issuance of certificate B failed; the CA complains that the public key has already been used. I assume that 4 and 5 were happening simultaneously, causing a race condition. What happened was that the certificate issuance fetched the request, determined the (likely) serial number of the next certificate (by looking at the serial file) and wrote the request to a file with this number. If this happens in two distinct instances before the first certificate is issues, the first request file is overwritten with the second. Let's have a look at the code (0.9.2 branch): lib/functions/crypto-utils.lib: sub crypto_write_tmp_csr { our ($errno, $errval, $tools); my $csr = $_[0]; my $tmpdir = getRequired ('TempDir'); my $ser = crypto_get_next_cert_serial (); ##// Let's save the request body to a temp file if (not $tools->saveFile( FILENAME => "$tmpdir/${ser}.req", DATA => $csr->getParsed()->{BODY}."\n" )) ... and sub crypto_create_cert { our ($errno, $errval, $tools, $cryptoShell); ... my $ser = crypto_get_next_cert_serial (); ... if ($days or $notafter or $notbefore) { ## Issue the Certificate with individual lifetime if ( not $token->issueCert( REQFILE => "$tmpdir/${ser}.req", ... If I am not mistaken, it is dangerous to write the request file to a file that is based on the assumed number of the next certificate, this extends the time frame in which a race condition with OpenSSL cert issuance can happen. At least the request file should be written to a unique temp file here. With the existing implementation it is very hard to avoid race conditions, because the OpenSSL index.txt and serial files are actually used by OpenCA. So there is little we can do in 0.9.2, I think. I have had a look at the code in CVS HEAD and it seems to me that the same or a similar problem is still there, but I think we can improve the situation here: Always write temporary request files to true temporary files unrelated to the assumed serial number (0.9.2 and HEAD) openssl.txt is already cleared before issuance, but this might still lead to race conditions when issuing to certs with identical DN. (HEAD) serial is read and written by OpenSSL and might also lead to race conditions. How about the following approach: Before each cert issuance do the following: 1 write request file to a unique temp file 2 create an empty unique temp file (index.txt dummy) 3a set a mutex 3b get the next serial number from the *database* 3c create a unique temp file (serial dummy) and write the expected serial number to the file 4 copy the required openssl config file to a temp file and change the 'database' entry to the file created in 2 and the 'serial' entry to the file created in 3. 5 issue the certificate with the temporary config file 6 clear the mutex I don't think we can do without the mutex without possibly creating 'holes' in the serial number sequence (if issuance for one certificate fails but succeeds for a second that is processed simultaneously). If we are ready to accept holes in the sequence, we can use a (database) sequence for the serial number instead of the mutex. This is obviously not an issue for CAs that use "concealed" (i. e. random) serial numbers. Ideas, comments? Anything we can do in this regard for 0.9.2? cu Martin ------------------------------------------------------- This SF.Net email is sponsored by the 'Do More With Dual!' webinar happening July 14 at 8am PDT/11am EDT. We invite you to explore the latest in dual core and dual graphics technology at this free one hour event hosted by HP, AMD, and NVIDIA. To register visit http://www.hp.com/go/dualwebinar _______________________________________________ OpenCA-Devel mailing list OpenCA-Devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openca-devel