Skip to content

Conversation

Stueypoo
Copy link
Contributor

@Stueypoo Stueypoo commented Jan 17, 2025

Describe your changes

  • Added an option to use an alternate CA certificate.

When importing certificates into a newly migrated CA, the code performs a certificate verification based upon the CA's current certificate. A problem with this occurs when the certificates being imported had been issued from one of the CA's earlier certificates (ie., the CA was renewed but active end-enty certificates still need to be imported).

To remedy this, a new "--cacert" option allows the Operator to provide the CA's previous certificate, and this CA certificate will then be used to verify the certificates being imported.

How has this been tested?

A systemtest has been ammended to test this change:
ant test:runone -Dtest.runone=CaImportCertDirCommandSystemTest

Checklist before requesting a review

  • [X ] I have performed a self-review of my code
  • [X ] I have kept the patch limited to only change the parts related to the patch
  • This change requires a documentation update

NOTE: This pull request is to replace #711

Added ability to provide an alternate CA certificate (for renewed CAs) and allow revocation details to be derived from the filename.
Added additional tests for changes to the associated client function.
@primetomas
Copy link
Collaborator

I'm sorry, but this fell between the chairs due to travels. If you rebase this one I promise to get it fixed for the next release.

@Stueypoo
Copy link
Contributor Author

Synced to latest keyfactor:main.

@primetomas
Copy link
Collaborator

Internal ticket tracker: ECA-13369

if ( sRevCode.equals("CESSATIONOFOPERATION")) sRevCode = "CESSATION_OF_OPERATION";
if ( sRevCode.equals("CERTIFICATEHOLD")) sRevCode = "CERTIFICATE_HOLD";
if ( sRevCode.equals("PRIVILEGESWITHDRAWN")) sRevCode = "PRIVILEGES_WITHDRAWN";
if ( sRevCode.equals("CERTIFICATEHOLD")) sRevCode = "AA_COMPROMISE";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug here in string names

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well spotted. Will fix that.

"Specify an alternate CA certificate file (in PEM). Use this option when importing certificates that were issued by the previous CA certificate. Please note that the supplied certificate is not verified."));
registerParameter(new Parameter(REVOKEDETAILS, "Revocation Details", MandatoryMode.OPTIONAL, StandaloneMode.FORBID, ParameterMode.FLAG,
"Revocation details are to be derived from the filename of the certificate. The filename must end with '!<REASON>!<INVALIDITY_TIME>'. The REASON can be the value or label as described in RFC5280 section 5.3.1. "
+ "INVALIDITY_TIME is formatted as '"+DATE_FORMAT_WINSAFE+"' and assumed to be the local timezone. Note: Filename extensions (ie., '.crt. or '.pem') are not supported. Please also note that any file without "
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would feel more consistent if revocation reason was an integer, the same as used when revoking certificates with ejbca.sh ra revokecert. Unessecary to have different parameters values in different places.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well it can be...I think the ability to use label complicates things and I would rather do without it. See RevokeCertificateCommand

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps. The CaImportCertCommand takes a text entry for revocation reason and not an integer code. The revocation reason text was confusing to me as the EJBCA's RevocationReason takes a different form than that in the RFC. I thought I'd allow an integer code, the RFC text label, as well as the EJBCA's text label.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

}

} catch (NumberFormatException e) {
// Not an integer, must be the full text
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could do without the full text imho. Keeping parameters simpler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See earlier comment.

// Find the revocation details from the filename. The details are separated with an exclamation (!) character.
final String[] sa = file.getName().split("!");
if (sa.length <3) {
log.error("ERROR: The revocation details are not found in filename '"+file.getName()+"'. Ignoring this file.");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simply ignoring a file makes the import process fragile. The import job reports error about succesful or non-succesful imports. Simply ignoring it here makes this reporting not reporting correctly. Either the report job should instead report that details was missing for this file and thus import failed, or we should allow missing revocation reason and then allowing "standard" import for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the operation is for a bulk set of files, the thinking here is to report an error, but allow the other files in the batch to be tried. Of course, if the whole batch is incorrectly labelled, then all files will show an error.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the skipping of import and error reporting should be part of the CertificateImporter then. If so it will be part of the import summary printed in the end.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really follow this comment. If the option to use '--revoke-details-in-filename' is enabled, then the code should report any issues with each filename in the directory being imported, especially if the Revocation Reason or Invalidity Time is not provided in the filename. The Operator should not use the option '--revoke-details-in-filename' if the certificate filenames do not include the extra revocation syntax in the filename.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But there is still some files will be imported that have the correct filename while other will be skipped with just a warning in the log that can easily disappear since it's only logged to the console. And in the end the command will state an "Import summary" which does not report anything on these skipped records. That is a bad "Import summary" imho. '--revoke-details-in-filename' should be robust against filenaming errors similar to it handling issuer errors, or errors with the file content being wrong. Wrong filename is a similar error to wrong file content and should be dealt with similarly.

This wh9le parsing for the reason code can be done in CertificateImporter instead, why not do it there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added any errors to the Results, so as to fix the Import Summary. Example below of 3 incorrect filenames:

ERROR: The revocation details are not found in filename 'A_15710.cer'. Ignoring this file.
ERROR: '2023.OCT.09-12.01' was not a valid revocation time. Use this time format 'yyyy.MM.dd-HH.mm'. Ignoring this file '2024_11.!6!2023.OCT.09-12.01'.
ERROR: 'KEYSCOMPROMISE' is not a valid revocation reason. Ignoring this file '2024_12!KEYSCOMPROMISE!2022.05.04-20.59'.

Import summary:
0 certificates were imported successfully.
Time: 0.0 seconds (Infinity tps)
3 certificates were not imported due to other errors.

The Revocation "Reason Code" is not checked by CertificateImporter, so checking it is legal needs to be done in this code..

Copy link
Contributor Author

@Stueypoo Stueypoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added replies and one code fix.

@primetomas
Copy link
Collaborator

I just though of a question on the revocation options. After importing certificates the CRL should also be imported which would also set the options of they are on the CRL. You anyhow must import the latest CRL for the CRL number to become correct.

Can you describe the benefits of this in addition to importing the CRL?
(I can think of some)

@Stueypoo
Copy link
Contributor Author

Stueypoo commented Jun 3, 2025 via email

@primetomas
Copy link
Collaborator

There is this command today: bin/ejbca.sh ca importcrl --help

@Stueypoo
Copy link
Contributor Author

Oh, I had not noticed the 'importcrl' command. I did some testing and this command works perfectly to revoke certs after importing them into the DB. I guess there isn't any real need for this pull request now. Feel free to cancel it.

@primetomas
Copy link
Collaborator

Great to hear it worked well. Perhaps we can point to the importcrl command in the help text for importcert?

@Stueypoo
Copy link
Contributor Author

Stueypoo commented Aug 1, 2025

I just realised that the --cacert option is still useful. I'll have another look at this and trim the change down.

@Stueypoo
Copy link
Contributor Author

Stueypoo commented Aug 9, 2025

Updates done to trim down code back to include the '--cacert' option only.

} finally {
fileOutputStream.close();
}
// Delete the CA
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the command doc says it is for old, i.e. renewed CA certificates. Wouldn't it make sense to renew the CA instead of deleting and re-creating it? See for example RenewCASystemTest for a simple example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good point. However the reason one would be importing certs into a new CA is that they are migrated an existing CA over to EJBCA. If this migrated CA had previous CA certs, then EJBCA does not know about them. This is reason to add the --cacert option to this command. Testing needs to follow that same process. If one was to renew the CA in EJBCA, then that CA would know the previous CA cert and the test may be flawed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants