Skip to content
Snippets Groups Projects
Commit 76928a3c authored by William Enright's avatar William Enright Committed by Larbi Gharib
Browse files

Restored OCSP endpoint, fixed response being signed with the wrong certificate

Change-Id: I4e81885a2252f01d7ae4507b1a1485c3527e4b87
parent 60a9c1e5
Branches
No related tags found
No related merge requests found
......@@ -41,6 +41,7 @@ import org.bouncycastle.cert.ocsp.OCSPResp;
import org.bouncycastle.jcajce.provider.asymmetric.X509;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.Base64;
......@@ -130,8 +131,8 @@ public class JamsCA implements CertificateAuthority {
}
}
public static OCSPResp getOCSPResponse(OCSPReq ocspRequest) throws OCSPException {
return ocspWorker.getOCSPResponse(ocspRequest);
public static OCSPResp getOCSPResponse(OCSPReq ocspRequest, X509Certificate certificate, PrivateKey privateKey, Boolean unknown) throws OCSPException {
return ocspWorker.getOCSPResponse(ocspRequest, certificate, privateKey, unknown);
}
@Override
......
......@@ -29,6 +29,7 @@ import net.jami.jams.ca.workers.csr.utils.ExtensionLibrary;
import net.jami.jams.common.objects.devices.Device;
import net.jami.jams.common.objects.user.User;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
......@@ -36,6 +37,11 @@ import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Date;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.AccessDescription;
import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
import org.bouncycastle.asn1.x509.Extension;
import static net.jami.jams.ca.workers.csr.CertificateWorker.SHIFT;
@Slf4j
......@@ -54,6 +60,22 @@ public class DeviceBuilder {
device.getCertificationRequest().getSubject(),
device.getCertificationRequest().getSubjectPublicKeyInfo()
);
/*
*
* This extension library configuration is done at this point in order to add the issuer id (here the jami Id)
* to the certificate to help retrieve the device certificate issuer in more suitable manner during the call to the OCSP endpoint
*
* */
//Pre-Define the AIA Point
AccessDescription accessDescription = new AccessDescription(
AccessDescription.id_ad_ocsp,
new GeneralName(GeneralName.uniformResourceIdentifier, JamsCA.serverDomain + "/api/ocsp/" + user.getJamiId())
);
ExtensionLibrary.deviceExtensions.getExtensions().add(new Object[]{Extension.authorityInfoAccess, false, new AuthorityInformationAccess(accessDescription)});
device.setCertificate(CertificateSigner.signCertificate(user.getPrivateKey(),builder, ExtensionLibrary.deviceExtensions));
boolean deviceIdDetected = false;
for(int i=0; i < device.getCertificationRequest().getSubject().getRDNs().length;i++) {
......
......@@ -78,7 +78,6 @@ public class ExtensionLibrary {
deviceExtensions.getExtensions().add(new Object[]{Extension.basicConstraints, true, new BasicConstraints(false)});
deviceExtensions.getExtensions().add(new Object[]{Extension.keyUsage, false, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.dataEncipherment | KeyUsage.keyAgreement | KeyUsage.nonRepudiation)});
deviceExtensions.getExtensions().add(new Object[]{Extension.cRLDistributionPoints, false, new CRLDistPoint(distPoints)});
deviceExtensions.getExtensions().add(new Object[]{Extension.authorityInfoAccess, false, new AuthorityInformationAccess(accessDescription)});
}
......
......@@ -23,12 +23,13 @@
package net.jami.jams.ca.workers.ocsp;
import lombok.extern.slf4j.Slf4j;
import net.jami.jams.ca.JamsCA;
import net.jami.jams.ca.workers.X509Worker;
import net.jami.jams.ca.workers.crl.CRLWorker;
import net.jami.jams.common.cryptoengineapi.ocsp.CertificateStatus;
import net.jami.jams.common.cryptoengineapi.ocsp.CertificateSummary;
import net.jami.jams.common.cryptoengineapi.ocsp.OCSPCertificateStatusMapper;
import net.jami.jams.common.objects.devices.Device;
import net.jami.jams.common.objects.user.User;
import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.Extensions;
......@@ -36,15 +37,7 @@ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CRLEntryHolder;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
import org.bouncycastle.cert.ocsp.BasicOCSPResp;
import org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder;
import org.bouncycastle.cert.ocsp.CertificateID;
import org.bouncycastle.cert.ocsp.OCSPException;
import org.bouncycastle.cert.ocsp.OCSPReq;
import org.bouncycastle.cert.ocsp.OCSPResp;
import org.bouncycastle.cert.ocsp.OCSPRespBuilder;
import org.bouncycastle.cert.ocsp.Req;
import org.bouncycastle.cert.ocsp.RespID;
import org.bouncycastle.cert.ocsp.*;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
import org.bouncycastle.operator.DigestCalculatorProvider;
......@@ -55,16 +48,13 @@ import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import static net.jami.jams.ca.JamsCA.CA;
import static net.jami.jams.ca.JamsCA.OCSP;
import static net.jami.jams.ca.JamsCA.crlLifetime;
import static net.jami.jams.ca.JamsCA.*;
@Slf4j
public class OCSPWorker extends X509Worker<String> {
......@@ -81,11 +71,11 @@ public class OCSPWorker extends X509Worker<String> {
DigestCalculatorProvider digestCalculatorProvider = new JcaDigestCalculatorProviderBuilder().setProvider("BC").build();
// only SHA-1 is supported for responder IDs.
this.responderID = new RespID(SubjectPublicKeyInfo.getInstance(CA.getCertificate().getPublicKey().getEncoded()), digestCalculatorProvider.get(new DefaultDigestAlgorithmIdentifierFinder().find ("SHA-1")));
this.contentSigner = new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").build(OCSP.getPrivateKey());
this.contentSigner = new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").build(CA.getPrivateKey());
log.info("Instantiated OCSP Worker...");
}
public OCSPResp getOCSPResponse(OCSPReq ocspRequest) throws OCSPException {
public OCSPResp getOCSPResponse(OCSPReq ocspRequest, X509Certificate certificate, PrivateKey privateKey, Boolean unknown) throws OCSPException {
try {
if(validateRequest(ocspRequest) != null) throw new OCSPException("Request is not valid"); //this means the request is invalid and we should notify the client.
//If the request was valid, we move on to other things.
......@@ -97,12 +87,13 @@ public class OCSPWorker extends X509Worker<String> {
if (nonceExtension != null) responseExtensions.add(nonceExtension);
Extension[] extensions = responseExtensions.toArray(new Extension[responseExtensions.size()]);
responseBuilder.setResponseExtensions(new Extensions(extensions));
for (Req request : ocspRequest.getRequestList()) {
addResponse(responseBuilder, request);
}
for (Req request : ocspRequest.getRequestList())
addResponse(responseBuilder, request, unknown);
BasicOCSPResp basicResponse = responseBuilder.build(
contentSigner,
new X509CertificateHolder[]{new JcaX509CertificateHolder(OCSP.getCertificate())},
new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").build(privateKey),
new X509CertificateHolder[]{new JcaX509CertificateHolder(certificate)},
new Date()
);
return new OCSPRespBuilder().build(OCSPRespBuilder.SUCCESSFUL, basicResponse);
......@@ -122,7 +113,15 @@ public class OCSPWorker extends X509Worker<String> {
}
private CertificateSummary getCertificateSummary(BigInteger serial) {
private CertificateSummary getCertificateSummary(BigInteger serial, Boolean unknown) {
if(unknown) {
return CertificateSummary.newBuilder()
.withStatus(CertificateStatus.UNKNOWN)
.withSerialNumber(serial)
.build();
}
X509CRLEntryHolder x509CRLEntryHolder = crlWorker.getExistingCRL().get().getRevokedCertificate(serial);
if(x509CRLEntryHolder != null) return CertificateSummary.newBuilder()
......@@ -137,7 +136,7 @@ public class OCSPWorker extends X509Worker<String> {
}
private void addResponse(BasicOCSPRespBuilder responseBuilder, Req request) throws OCSPException{
private void addResponse(BasicOCSPRespBuilder responseBuilder, Req request, Boolean unknown) throws OCSPException{
CertificateID certificateID = request.getCertID();
// Build Extensions
Extensions extensions = new Extensions(new Extension[]{});
......@@ -147,7 +146,7 @@ public class OCSPWorker extends X509Worker<String> {
if (nonceExtension != null) extensions = new Extensions(nonceExtension);
}
responseBuilder.addResponse(certificateID,
OCSPCertificateStatusMapper.getStatus(getCertificateSummary(request.getCertID().getSerialNumber())),
OCSPCertificateStatusMapper.getStatus(getCertificateSummary(request.getCertID().getSerialNumber(), unknown)),
new Date(),
new Date(new Date().getTime() + crlLifetime),
extensions);
......
......@@ -27,46 +27,96 @@ import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import net.jami.jams.ca.JamsCA;
import net.jami.jams.common.utils.X509Utils;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
import org.bouncycastle.cert.ocsp.CertificateID;
import net.jami.jams.common.dao.StatementElement;
import net.jami.jams.common.dao.StatementList;
import net.jami.jams.common.objects.devices.Device;
import net.jami.jams.common.objects.user.User;
import org.bouncycastle.cert.ocsp.OCSPReq;
import org.bouncycastle.cert.ocsp.OCSPReqBuilder;
import org.bouncycastle.cert.ocsp.OCSPResp;
import org.bouncycastle.operator.DigestCalculator;
import org.bouncycastle.operator.DigestCalculatorProvider;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.cert.ocsp.Req;
import java.io.IOException;
import java.security.cert.X509Certificate;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
@WebServlet("/api/ocsp")
import static net.jami.jams.server.Server.dataStore;
@WebServlet("/api/ocsp/*")
public class OCSPServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.sendError(404);
// resp.setContentType("application/ocsp-response");
// byte[] content = new byte[Integer.parseInt(req.getHeader("Content-Length"))];
// try {
// for(int i=0;i<content.length;i++)
// req.getInputStream().read(content);
//
// OCSPReq ocspReq = new OCSPReq(content);
// OCSPResp response = JamsCA.getOCSPResponse(ocspReq);
// if (response != null) {
// byte[] respBytes = response.getEncoded();
// resp.getOutputStream().write(respBytes);
// } else resp.setStatus(404);
//
// }
// catch (Exception e) {
// resp.sendError(404, "Could not find the requested certificate!");
// }
resp.setContentType("application/ocsp-response");
byte[] content = new byte[Integer.parseInt(req.getHeader("Content-Length"))];
try {
for(int i=0;i<content.length;i++)
req.getInputStream().read(content);
OCSPReq ocspReq = new OCSPReq(content);
List<BigInteger> ids = new ArrayList<>();
for (Req request : ocspReq.getRequestList())
ids.add(request.getCertID().getSerialNumber());
String issuerId = req.getPathInfo().replace("/","");
/*
* If there is no issue id we are dealing with a certificate signed byt the CA root
* Else the certificate is a device certificate signed by a user with and the issuerId is his Jami Id
*/
if(issuerId == ""){
OCSPResp response = JamsCA.getOCSPResponse(ocspReq, JamsCA.CA.getCertificate(), JamsCA.CA.getPrivateKey(), false);
if (response != null) {
byte[] respBytes = response.getEncoded();
resp.getOutputStream().write(respBytes);
} else resp.setStatus(404);
}
else {
User targetUser = null;
StatementList userStatementsList = new StatementList();
StatementElement usernameStatement = new StatementElement("jamiId", "=", issuerId, "");
userStatementsList.addStatement(usernameStatement);
try {
targetUser = dataStore.getUserDao().getObjects(userStatementsList).get(0);
StatementList deviceStatementsList = new StatementList();
StatementElement deviceOwnerStatement = new StatementElement("owner", "=", targetUser.getUsername(), "");
deviceStatementsList.addStatement(deviceOwnerStatement);
List<Device> devices = dataStore.getDeviceDao().getObjects(deviceStatementsList);
boolean deviceDoesNotExist = true;
for (Device d: devices) {
for (BigInteger id: ids) {
if (d.getCertificate().getSerialNumber().equals(id)) {
deviceDoesNotExist= false;
}
}
}
OCSPResp response = null;
if(deviceDoesNotExist){
response = JamsCA.getOCSPResponse(ocspReq, targetUser.getCertificate(), targetUser.getPrivateKey(), true);
}
else{
response = JamsCA.getOCSPResponse(ocspReq, targetUser.getCertificate(), targetUser.getPrivateKey(), false);
}
if (response != null) {
byte[] respBytes = response.getEncoded();
resp.getOutputStream().write(respBytes);
} else resp.setStatus(404);
}
catch (Exception e) {
resp.sendError(404, "Could not find the requested certificate!");
}
}
}
catch (Exception e) {
resp.sendError(404, "Could not find the requested certificate!");
}
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment