Comments (8)
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.
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.
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.
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.
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.
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.
@shred What other services is acme4j compatible with? Does it support ZeroSSL?
from acme4j.
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)
- The challenge status is always "INVALID" HOT 5
- The challenge status was always "INVALID" HOT 13
- http://${domain}/.well-known/acme-challenge/${token}
- acme4j example is creating zero- length crt files HOT 10
- preferred-chain attribute, for alternate chains HOT 2
- Can only parse traditional files HOT 2
- EAB HMAC keys with arbitrary lengths HOT 5
- CVE-2023-33201 from Bouncy Castle HOT 8
- add utils to do pre validation or help
- Is there a way to keep txt unchanged and verify twice? HOT 2
- New account registration HOT 1
- Bouncy Castel dependency? HOT 9
- Allow to pass query parameters in directory URL HOT 2
- Provide example showing how to save and load existing certificates HOT 2
- AcmeJsonResource#update throws AcmeRetryAfterException even if resource is ready HOT 3
- Abstract away certificate renewal HOT 6
- response is not reading correctly HOT 3
- Java 22 Support HOT 1
- OrderBuilder.replaces() functions assume auto-renewal support by the server HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from acme4j.