GithubHelp home page GithubHelp logo

Comments (8)

shred avatar shred commented on July 28, 2024 1

acme4j is designed to be a generic ACME client in first place, so it is compatible with all CAs that are RFC 8555 compliant. It is best tested with Let's Encrypt though.

ZeroSSL should work. You can connect to their servers by using the https://acme.zerossl.com/v2/DV90 URI (instead of acme://letsencrypt.org).

from acme4j.

cowwoc avatar cowwoc commented on July 28, 2024

I think I get it now. If I create an order asking for a new Certificate and the status of the request comes back with VALID then it means that a certificate already exists and does not need to be renewed. Is that correct?

from acme4j.

shred avatar shred commented on July 28, 2024

I think I get it now. If I create an order asking for a new Certificate and the status of the request comes back with VALID then it means that a certificate already exists and does not need to be renewed. Is that correct?

No. If the certificate has the status VALID, it only means that the certificate has been created and is in a downloadable state. It does not reflect whether the certificate has expired or not. You also wouldn't want to wait with renewal until the cert has already been expired.

This is a way to get the RenewalInfo object: If you got your certificate, you can use the Certificate.getLocation() method to retrieve the URL of the certificate on CA side. You can store this URL somewhere, e.g. in a database. To recreate the Certificate object at a later stage, you can invoke Login.bindCertificate(certificateUrl). Then you can invoke Certificate.getRenewalInfo() and get the RenewalInfo object.

Example:

Certificate cert = // the certificate that was freshly created
URL certLocation = cert.getLocation();
// store certLocation somewhere

Then, as soon as you need the RenewalInfo:

Login login = // your login
URL certLocation = // certLocation that was stored
Certificate cert = login.bindCertificate(certLocation);
RenewalInfo renewalInfo = cert.getRenewalInfo();

Anyhow I just realized that this way is unnecessary complicated. I will think about an improved way, which directly uses the X509Certificate object. I will keep this issue open, and report back as soon as it is available.

Note that RenewalInfo must be supported by the CA, otherwise getRenewalInfo() will throw an exception. To generally find out if a certificate will expire soon, you can also use the X509Certificate.getNotAfter() method to read the certificate's expiry date.

from acme4j.

shred avatar shred commented on July 28, 2024

A better way (which still requires storing an URL though):

Certificate cert = // the certificate that was freshly created
Optional<URL> renewalInfoLocation = cert.getRenewalInfoLocation();
// Store the renewalInfoLocation somewhere. Will be empty if renewalInfo is not supported.

Then later:

Login login = // your login
URL renewalInfoLocation = // renewalInfoLocation that was stored
RenewalInfo renewalInfo = login.bindRenewalInfo(renewalInfoLocation);

The "improved way" which I mentioned above will not require to store an URL, but it will require draft-ietf-acme-ari-02, which is not supported yet.

from acme4j.

cowwoc avatar cowwoc commented on July 28, 2024

My incentive for asking this question is that Let's Encrypt has rate limits of issuing 5 certificates per week (for the same domains). I don't want to cross this limit, but even time I deploy a new server to production it restarts acme4j and goes through the certificate renewal process all over again.

At what step does acme4j ask for a new certificate? Is it Order.execute(Keypair domainKeyPair)? Can I run the following code indefinitely without triggering their limit?

// Order the certificate
Order order = account.newOrder().domains(domains).create();

// Perform all required authorizations
for (Authorization auth : order.getAuthorizations())
	verify(auth);

if (order.getStatus() == Status.VALID)
{
	Certificate certificate = order.getCertificate();
	X509Certificate x509Certificate = certificate.getCertificate();
	Date endTime = x509Certificate.getNotAfter();
	Instant now = Instant.now();
	Duration timeLeft = Duration.between(now, endTime.toInstant());
	if (timeLeft.compareTo(MIN_TIME_LEFT) > 0)
	{
		// No need to renew certificate
		return certificate;
	}	
}
// Otherwise, renew certificate

This way I wouldn't need to store the certificate anywhere. I would just download it on demand.

Can you please update the example code and documentation (Javadoc and main doc) to tackle this use-case. Also, it would be helpful if you indicates that getRenewalInfo() may not be supported by the server. As it stands, the @return Javadoc indicates that a value is always returned.

Thank you.

from acme4j.

shred avatar shred commented on July 28, 2024

With account.newOrder() you won't retrieve an existing order/certificate, but prepare to creating a new one.

The ACME protocol provides a way to fetch all existing orders that are related to your account, and acme4j offers access to this information with Account.getOrders(). But although this field is mandatory according to RFC 8555, it is not implemented at Let's Encrypt. See letsencrypt/boulder#3335 and #74.

So if you use Let's Encrypt, I see no other way than to either store the order or certificate URLs locally, or check your locally stored certificate for expiration. However, checking x509Certificate.getNotAfter() is the correct way to find out if your certificate needs to be renewed soon.

I will review the RenewalInfo references in the Javadocs and documentation, and mention that it needs to be supported by the CA.

from acme4j.

cowwoc avatar cowwoc commented on July 28, 2024

@shred What other services is acme4j compatible with? Does it support ZeroSSL?

from acme4j.

cowwoc avatar cowwoc commented on July 28, 2024

Thank you. I will close this issue, seeing as ZeroSSL doesn't have rate limits. I will just issue a new certificate on every startup for now, and eventually I'll add state to the database to avoid unnecessary renews.

from acme4j.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.