package org.signserver.validationservice.server; import org.signserver.common.*; import org.signserver.common.util.*; import org.signserver.common.dbdao.*; import org.signserver.ejb.interfaces.IWorkerSession; import org.signserver.server.WorkerContext; import org.signserver.server.signers.BaseSigner; import javax.persistence.EntityManager; import org.signserver.server.archive.Archivable; import org.signserver.server.archive.DefaultArchivable; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import java.net.HttpURLConnection; import java.net.URL; import java.security.Security; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateFactory; import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.util.*; import javax.xml.bind.DatatypeConverter; import org.openxml4j.opc.Package; import org.openxml4j.exceptions.InvalidFormatException; import org.openxml4j.exceptions.OpenXML4JException; import org.openxml4j.opc.PackageAccess; import org.openxml4j.opc.PackagePart; import org.openxml4j.opc.signature.PackageDigitalSignature; import org.openxml4j.opc.signature.PackageDigitalSignatureManager; import org.openxml4j.opc.signature.VerifyResult; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers; import org.bouncycastle.asn1.x509.X509Extension; import org.bouncycastle.asn1.x509.X509Extensions; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.ocsp.BasicOCSPResp; import org.bouncycastle.ocsp.CertificateID; import org.bouncycastle.ocsp.OCSPReq; import org.bouncycastle.ocsp.OCSPReqGenerator; import org.bouncycastle.ocsp.OCSPResp; import org.bouncycastle.ocsp.OCSPRespStatus; import org.bouncycastle.ocsp.SingleResp; import org.odftoolkit.odfdom.doc.OdfDocument; import org.odftoolkit.odfdom.pkg.signature.DocumentSignature; import org.odftoolkit.odfdom.pkg.signature.DocumentSignatureGroup; import org.odftoolkit.odfdom.pkg.signature.DocumentSignatureManager; import org.odftoolkit.odfdom.pkg.signature.DocumentSignatureVerifyResult; import org.odftoolkit.odfdom.pkg.signature.SignatureCreationMode; import java.sql.SQLException; import java.util.Date; import java.util.LinkedList; import java.util.List; import org.apache.log4j.Logger; import org.signserver.server.BaseProcessable; import org.signserver.validationservice.common.ValidateRequest; import org.signserver.validationservice.common.ValidationServiceConstants; public class OOXMLValidator extends BaseProcessable { private IValidationService validationService; private List fatalErrors; private static final Logger LOG = Logger.getLogger(OOXMLValidator.class); private static final String CONTENT_TYPE = "text/xml"; private int ResponseCode = Defines.CODE_INVALIDSIGNATURE;; private String ResponseMessage = Defines.ERROR_INVALIDSIGNATURE; private static String WORKERNAME = "OOXMLValidator"; private List listSignerInfoResponse; @Override public void init(int workerId, WorkerConfig config, WorkerContext workerContext, EntityManager workerEM) { // TODO Auto-generated method stub super.init(workerId, config, workerContext, workerEM); fatalErrors = new LinkedList(); try { validationService = createValidationService(config); } catch (SignServerException e) { final String error = "Could not get crypto token: " + e.getMessage(); LOG.error(error); fatalErrors.add(error); } } /** * Creating a Validation Service depending on the TYPE setting * @param config configuration containing the validation service to create * @return a non initialized group key service. */ private IValidationService createValidationService(WorkerConfig config) throws SignServerException { String classPath = config.getProperties().getProperty(ValidationServiceConstants.VALIDATIONSERVICE_TYPE, ValidationServiceConstants.DEFAULT_TYPE); IValidationService retval = null; String error = null; try { if (classPath != null) { Class implClass = Class.forName(classPath); retval = (IValidationService) implClass.newInstance(); retval.init(workerId, config, em, getCryptoToken()); } } catch (ClassNotFoundException e) { error = "Error instatiating Validation Service, check that the TYPE setting of workerid : " + workerId + " have the correct class path."; //DBConnector.getInstances().writeLogToDataBaseOutside(WORKERNAME, "SYSTEM", "[ClassNotFoundException] "+error, 214); LOG.error(error, e); } catch (IllegalAccessException e) { error = "Error instatiating Validation Service, check that the TYPE setting of workerid : " + workerId + " have the correct class path."; //DBConnector.getInstances().writeLogToDataBaseOutside(WORKERNAME, "SYSTEM", "[IllegalAccessException] "+error, 214); LOG.error(error, e); } catch (InstantiationException e) { error = "Error instatiating Validation Service, check that the TYPE setting of workerid : " + workerId + " have the correct class path."; //DBConnector.getInstances().writeLogToDataBaseOutside(WORKERNAME, "SYSTEM", "[InstantiationException] "+error, 214); LOG.error(error, e); } if (error != null) { fatalErrors.add(error); } return retval; } /** * @see org.signserver.server.BaseProcessable#getStatus() */ @Override public WorkerStatus getStatus(final List additionalFatalErrors) { return validationService.getStatus(); } @Override protected List getFatalErrors() { final List errors = new LinkedList(); errors.addAll(super.getFatalErrors()); errors.addAll(fatalErrors); return errors; } @Override public ProcessResponse processData(ProcessRequest signRequest, RequestContext requestContext) throws IllegalRequestException, CryptoTokenOfflineException, SignServerException { // TODO Auto-generated method stub ProcessResponse signResponse; // Check that the request contains a valid GenericSignRequest object // with a byte[]. //final String userContract = RequestMetadata.getInstance(requestContext).get("UsernameContract"); if (!(signRequest instanceof GenericSignRequest)) { //DBConnector.getInstances().writeLogToDataBaseOutside(WORKERNAME, userContract, "[IllegalRequestException] Server: Recieved request wasn't a expected GenericSignRequest.", 201); throw new IllegalRequestException( "Recieved request wasn't a expected GenericSignRequest."); } final ISignRequest sReq = (ISignRequest) signRequest; if (!(sReq.getRequestData() instanceof byte[])) { //DBConnector.getInstances().writeLogToDataBaseOutside(WORKERNAME, userContract, "[IllegalRequestException] Server: Recieved request data wasn't a expected byte[].", 202); throw new IllegalRequestException( "Recieved request data wasn't a expected byte[]."); } byte[] data = (byte[]) sReq.getRequestData(); final String archiveId = createArchiveId(data, (String) requestContext.get(RequestContext.TRANSACTION_ID)); // if(DBConnector.getInstances().getAgreementStatusUser(userContract) != 1) // { // return new GenericSignResponse(sReq.getRequestID(), archiveId, 212, "Contract is locked or invalid"); // } // statisticTimeOfValidating(userContract); String channelName = RequestMetadata.getInstance(requestContext).get(Defines._CHANNEL); String user = RequestMetadata.getInstance(requestContext).get(Defines._USER); Security.addProvider(new BouncyCastleProvider()); ArrayList caProviders = new ArrayList(); listSignerInfoResponse = new ArrayList(); caProviders = DBConnector.getInstances().getCAProviders(); boolean isVerified = false; try { String serialNumber = getSerialNumber(requestContext); isVerified = Verify(channelName, user, data, serialNumber, caProviders); } catch(Exception e) { e.printStackTrace(); e.printStackTrace(); return new GenericSignResponse(sReq.getRequestID(), archiveId , Defines.CODE_INTERNALSYSTEM, Defines.ERROR_INTERNALSYSTEM+": "+e.getMessage()); } byte[] byteResponse; if(isVerified) byteResponse = "OK".getBytes(); else byteResponse = "FAILED".getBytes(); final Collection archivables = Arrays.asList(new DefaultArchivable(Archivable.TYPE_RESPONSE, CONTENT_TYPE, byteResponse, archiveId)); if (signRequest instanceof GenericServletRequest) { signResponse = new GenericServletResponse(sReq.getRequestID(), byteResponse, getSigningCertificate(), archiveId, archivables, CONTENT_TYPE); } else { signResponse = new GenericSignResponse(sReq.getRequestID(), byteResponse , getSigningCertificate(), null, archiveId, archivables , ResponseCode, ResponseMessage, listSignerInfoResponse); } return signResponse; } public boolean Verify(String channelName, String user, byte[] ooxmlfile, String serialNumber, ArrayList caProviders) throws Exception { Package docxpackage = Package.open(new ByteArrayInputStream(ooxmlfile) , PackageAccess.READ_WRITE); PackageDigitalSignatureManager dsm = new PackageDigitalSignatureManager(docxpackage); if(!dsm.getIsSigned()) { ResponseCode = Defines.CODE_SIGNEDDOC; ResponseMessage = Defines.ERROR_SIGNEDDOC; return false; } BigInteger serialNo = new BigInteger(serialNumber, 16); boolean isSignatureValid = false; List pks = dsm.getSignatures(); for(int i=0; i