Set a RevocationReason on certificate revocation

pull/30/head
Richard Körber 2016-07-07 00:12:06 +02:00
parent 78cb7259d4
commit 42e94125d8
5 changed files with 118 additions and 0 deletions

View File

@ -148,6 +148,18 @@ public class Certificate extends AcmeResource {
* Revokes this certificate.
*/
public void revoke() throws AcmeException {
revoke(null);
}
/**
* Revokes this certificate.
*
* @param reason
* {@link RevocationReason} stating the reason of the revocation that is
* used when generating OCSP responses and CRLs. {@code null} to give no
* reason.
*/
public void revoke(RevocationReason reason) throws AcmeException {
LOG.debug("revoke");
URI resUri = getSession().resourceUri(Resource.REVOKE_CERT);
if (resUri == null) {
@ -162,6 +174,9 @@ public class Certificate extends AcmeResource {
ClaimBuilder claims = new ClaimBuilder();
claims.putResource(Resource.REVOKE_CERT);
claims.putBase64("certificate", cert.getEncoded());
if (reason != null) {
claims.put("reason", reason.getReasonCode());
}
int rc = conn.sendSignedRequest(resUri, claims, getSession());
if (rc != HttpURLConnection.HTTP_OK) {

View File

@ -0,0 +1,65 @@
/*
* acme4j - Java ACME client
*
* Copyright (C) 2016 Richard "Shred" Körber
* http://acme4j.shredzone.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
package org.shredzone.acme4j;
/**
* Enumeration of revocation reasons.
*
* @see <a href="https://tools.ietf.org/html/rfc5280#section-5.3.1">RFC 5280 Section
* 5.3.1</a>
* @author Richard "Shred" Körber
*/
public enum RevocationReason {
UNSPECIFIED(0),
KEY_COMPROMISE(1),
CA_COMPROMISE(2),
AFFILIATION_CHANGED(3),
SUPERSEDED(4),
CESSATION_OF_OPERATION(5),
CERTIFICATE_HOLD(6),
REMOVE_FROM_CRL(8),
PRIVILEGE_WITHDRAWN(9),
AA_COMPROMISE(10);
/**
* Returns the {@link RevocationReason} that matches the reason code.
*
* @param reasonCode
* Reason code as defined in RFC 5280
* @return Matching {@link RevocationReason}, or {@code null} if not known
*/
public static RevocationReason code(int reasonCode) {
for (RevocationReason rr : values()) {
if (rr.reasonCode == reasonCode) {
return rr;
}
}
return null;
}
private final int reasonCode;
private RevocationReason(int reasonCode) {
this.reasonCode = reasonCode;
}
/**
* Returns the reason code as defined in RFC 5280.
*/
public int getReasonCode() {
return reasonCode;
}
}

View File

@ -109,4 +109,29 @@ public class CertificateTest {
provider.close();
}
/**
* Test that a certificate can be revoked with reason.
*/
@Test
public void testRevokeCertificateWithReason() throws AcmeException, IOException {
final X509Certificate originalCert = TestUtils.createCertificate();
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session) {
assertThat(uri, is(resourceUri));
assertThat(claims.toString(), sameJSONAs(getJson("revokeCertificateWithReasonRequest")));
assertThat(session, is(notNullValue()));
return HttpURLConnection.HTTP_OK;
}
};
provider.putTestResource(Resource.REVOKE_CERT, resourceUri);
Certificate cert = new Certificate(provider.createSession(), locationUri, null, originalCert);
cert.revoke(RevocationReason.KEY_COMPROMISE);
provider.close();
}
}

View File

@ -138,6 +138,13 @@ revokeCertificateRequest = \
"resource":"revoke-cert"\
}
revokeCertificateWithReasonRequest = \
{\
"certificate": "MIIDVzCCAj-gAwIBAgIJAM4KDTzb0Y7NMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQwHhcNMTUxMjEwMDAxMTA4WhcNMjUxMjA3MDAxMTA4WjBCMQswCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr0g3w4C8xbj_5lzJiDxk0HkEJeZeyruq-0AzOPMigJZ7zxZtX_KUxOIHrQ4qjcFhl0DmQImoM0wESU-kcsjAHCx8E1lgRVlVsMfLAQPHkg5UybqfadzKT3ALcSD-9F9mVIP6liC_6KzLTASmx6zM7j92KTl1ArObZr5mh0jvSNORrMhEC4Byn3-NTxjuHON1rWppCMwpeNNhFzaAig3O8PY8IyaLXNP2Ac5pXn0iW16S-Im9by7751UeW5a7DznmuMEM-WY640ffJDQ4-I64H403uAgvvSu-BGw8SEEZGuBCxoCnG1g6y6OvJyN5TgqFdGosAfm1u-_MP1seoPdpBQIDAQABo1AwTjAdBgNVHQ4EFgQUrie5ZLOrA_HuhW1b_CHjzEvj34swHwYDVR0jBBgwFoAUrie5ZLOrA_HuhW1b_CHjzEvj34swDAYDVR0TBAUwAwEB_zANBgkqhkiG9w0BAQsFAAOCAQEAkSOP0FUgIIUeJTObgXrenHzZpLAkqXi37dgdYuPhNveo3agueP51N7yIoh6YGShiJ73Rvr-lVYTwFXStrLih1Wh3tWvksMxnvocgd7l6USRb5_AgH7eHeFK4DoCAak2hUAcCLDRJN3XMhNLpyJhw7GJxowVIGUlxcW5Asrmh9qflfyMyjripTP3CdHobmNcNHyScjNncKj37m8vomel9acekTtDl2Ci7nLdE-3VqQCXMIfLiF3PO0gGpKei0RuVCSOG6W83zVInCPd_l3aluSR-f_VZlk8KGQ4As4uTQi89j-J1YepzG0ASMZpjVbXeIg5QBAywVxBh5XVTz37KN8A",\
"resource":"revoke-cert",\
"reason": 1\
}
authorizationChallenges = \
{\
"challenges": [\

View File

@ -102,3 +102,9 @@ To revoke a certificate, just invoke the respective method:
```java
cert.revoke();
```
Optionally, you can provide a revocation reason that the ACME server may use when generating OCSP responses and CRLs.
```java
cert.revoke(RevocationReason.KEY_COMPROMISE);
```