diff --git a/docs/source/certificate-revocation.rst b/docs/source/certificate-revocation.rst index 0dbcea21c7..f6a7e31ab5 100644 --- a/docs/source/certificate-revocation.rst +++ b/docs/source/certificate-revocation.rst @@ -38,7 +38,21 @@ Submission of the certificate revocation requests expects the following fields t :legalName: Legal name associated with the certificate that is to be revoked. -:reason: Revocation reason (as specified in the java.security.cert.CRLReason). +:reason: Revocation reason (as specified in the java.security.cert.CRLReason). The following values are allowed. + + :UNSPECIFIED: This reason indicates that it is unspecified as to why the certificate has been revoked. + + :KEY_COMPROMISE: This reason indicates that it is known or suspected that the certificate subject's private key has been compromised. It applies to end-entity certificates only. + + :CA_COMPROMISE: This reason indicates that it is known or suspected that the certificate subject's private key has been compromised. It applies to certificate authority (CA) certificates only. + + :AFFILIATION_CHANGED: This reason indicates that the subject's name or other information has changed. + + :SUPERSEDED: This reason indicates that the certificate has been superseded. + + :CESSATION_OF_OPERATION: This reason indicates that the certificate is no longer needed. + + :PRIVILEGE_WITHDRAWN: This reason indicates that the privileges granted to the subject of the certificate have been withdrawn. :reporter: Issuer of this certificate revocation request. diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/PersistentCertificateRevocationRequestStorage.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/PersistentCertificateRevocationRequestStorage.kt index 54f97739bd..5aa48177c4 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/PersistentCertificateRevocationRequestStorage.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/common/persistence/PersistentCertificateRevocationRequestStorage.kt @@ -10,13 +10,27 @@ import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.DatabaseTransaction import net.corda.nodeapi.internal.persistence.TransactionIsolationLevel import java.math.BigInteger +import java.security.cert.CRLReason import java.security.cert.X509Certificate import java.time.Instant class PersistentCertificateRevocationRequestStorage(private val database: CordaPersistence) : CertificateRevocationRequestStorage { + private companion object { + val ALLOWED_REASONS = arrayOf( + CRLReason.KEY_COMPROMISE, + CRLReason.AFFILIATION_CHANGED, + CRLReason.CA_COMPROMISE, + CRLReason.CESSATION_OF_OPERATION, + CRLReason.PRIVILEGE_WITHDRAWN, + CRLReason.SUPERSEDED, + CRLReason.UNSPECIFIED + ) + } + override fun saveRevocationRequest(request: CertificateRevocationRequest): String { return database.transaction(TransactionIsolationLevel.SERIALIZABLE) { // Get matching CSR + validate(request) val csr = retrieveCsr(request.certificateSerialNumber, request.csrRequestId, request.legalName) csr ?: throw IllegalArgumentException("No CSR matching the given criteria was found") // Check if there is an entry for the given certificate serial number @@ -45,6 +59,10 @@ class PersistentCertificateRevocationRequestStorage(private val database: CordaP } } + private fun validate(request:CertificateRevocationRequest) { + require(request.reason in ALLOWED_REASONS) { "The given revocation reason is not allowed." } + } + private fun DatabaseTransaction.retrieveCsr(certificateSerialNumber: BigInteger?, csrRequestId: String?, legalName: CordaX500Name?): CertificateSigningRequestEntity? { val csr = if (csrRequestId != null) { uniqueEntityWhere { builder, path -> diff --git a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/webservice/CertificateRevocationRequestWebService.kt b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/webservice/CertificateRevocationRequestWebService.kt index 65a1e25ec0..310b94bbe5 100644 --- a/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/webservice/CertificateRevocationRequestWebService.kt +++ b/network-management/src/main/kotlin/com/r3/corda/networkmanage/doorman/webservice/CertificateRevocationRequestWebService.kt @@ -3,6 +3,7 @@ package com.r3.corda.networkmanage.doorman.webservice import com.r3.corda.networkmanage.doorman.signer.CrrHandler import com.r3.corda.networkmanage.doorman.webservice.CertificateRevocationRequestWebService.Companion.CRR_PATH import net.corda.core.serialization.deserialize +import net.corda.core.utilities.contextLogger import net.corda.nodeapi.internal.network.CertificateRevocationRequest import java.io.InputStream import javax.ws.rs.Consumes @@ -12,20 +13,30 @@ import javax.ws.rs.Produces import javax.ws.rs.core.MediaType import javax.ws.rs.core.Response import javax.ws.rs.core.Response.ok +import javax.ws.rs.core.Response.status @Path(CRR_PATH) class CertificateRevocationRequestWebService(private val crrHandler: CrrHandler) { companion object { const val CRR_PATH = "certificate-revocation-request" + val logger = contextLogger() } @POST @Consumes(MediaType.APPLICATION_OCTET_STREAM) @Produces(MediaType.TEXT_PLAIN) fun submitRequest(input: InputStream): Response { - val request = input.readBytes().deserialize() - val requestId = crrHandler.saveRevocationRequest(request) - return ok(requestId).build() + return try { + val request = input.readBytes().deserialize() + val requestId = crrHandler.saveRevocationRequest(request) + ok(requestId) + } catch (e: Exception) { + logger.warn("Unable to process the revocation request.", e) + when (e) { + is IllegalArgumentException -> status(Response.Status.BAD_REQUEST).entity(e.message) + else -> throw e + } + }.build() } } \ No newline at end of file