New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BDOC signatures with same <xades:SigningTime> after serialization #4

Closed
antonioaraujob opened this Issue Aug 14, 2015 · 6 comments

Comments

Projects
None yet
2 participants
@antonioaraujob

antonioaraujob commented Aug 14, 2015

Dear friends of open-eid, I hope you are fine.

I am signing a BDOC container several times using the following steps:

Create the container:

  • create a BDOC container
  • add a file (DataFile)
  • serialize the container

Sign the container (two steps signing):

  • deserialize the container (previously created)
  • create signature parameters and signature production place
  • get the hash to sign in the server side
  • serialize the container
  • sign the hash in the client side (EstEID plug-in)
  • receive the signature
  • deserialize the container
  • add the signature (Container.signRaw)
  • serialize container

After applying three signatures to the container, these signatures have the same property <xades:SigningTime>2015-08-14T18:36:32Z</xades:SigningTime>. The signatures were made in different moments, in fact if I inspect the container content I can see that the files signatures0.xml, signatures1.xml and signatures2.xml have different modification time.

Could anyone give me a hint to find out what I am doing wrong please?.

If you wish to view the container it is available here.

Best regards

@antonioaraujob

This comment has been minimized.

Show comment
Hide comment
@antonioaraujob

antonioaraujob Aug 18, 2015

One more question:
I deserialized a previously serialized container in order to know how many DataFiles or signatures the container has and then I tried to save the container to disk ( save(java.lang.String path) ):

public String serialize()  {
        logger.debug("recurso /serializar");        
        Security.addProvider(new BouncyCastleProvider());       
        Container c;
        try {
            c = deserialize("/tmp/murachi/a52e340a-2d27-4b29-8b4c-4c4d7226fcaa-serialized.bin");
            logger.debug("deserialized container");         
            logger.debug("signatures: "+ Integer.toString(c.getSignatures().size()));
            c.save("/tmp/prueba.bdoc");                 
        } catch (ClassNotFoundException | IOException e) {
            e.printStackTrace();            
            logger.error("ClassNotFoundException | IOException e");
            return "error ClassNotFoundException | IOException e";          
        }           
        return "success";
    }

but I got the following exception:
SEVERE: El Servlet.service() para el servlet [Murachi] en el contexto con ruta [/Murachi] lanzó la excepción [eu.europa.ec.markt.dss.exception.DSSException: java.io.FileNotFoundException: File '/tmp/murachi/a52e340a-2d27-4b29-8b4c-4c4d7226fcaa.bdoc' does not exist] con causa raíz java.io.FileNotFoundException: File '/tmp/murachi/a52e340a-2d27-4b29-8b4c-4c4d7226fcaa.bdoc' does not exist at eu.europa.ec.markt.dss.DSSUtils.openInputStream(DSSUtils.java:1575) at eu.europa.ec.markt.dss.DSSUtils.toInputStream(DSSUtils.java:1430) at eu.europa.ec.markt.dss.signature.FileDocument.openStream(FileDocument.java:72) at eu.europa.ec.markt.dss.signature.FileDocument.save(FileDocument.java:106) at org.digidoc4j.impl.BDocContainer.save(BDocContainer.java:574) ...

It appears that it is not possible to save a container after deserializing it. Is this an invalid use of serialize and deserialize functions? I tried to follow this example. Any comment?

Best regards

antonioaraujob commented Aug 18, 2015

One more question:
I deserialized a previously serialized container in order to know how many DataFiles or signatures the container has and then I tried to save the container to disk ( save(java.lang.String path) ):

public String serialize()  {
        logger.debug("recurso /serializar");        
        Security.addProvider(new BouncyCastleProvider());       
        Container c;
        try {
            c = deserialize("/tmp/murachi/a52e340a-2d27-4b29-8b4c-4c4d7226fcaa-serialized.bin");
            logger.debug("deserialized container");         
            logger.debug("signatures: "+ Integer.toString(c.getSignatures().size()));
            c.save("/tmp/prueba.bdoc");                 
        } catch (ClassNotFoundException | IOException e) {
            e.printStackTrace();            
            logger.error("ClassNotFoundException | IOException e");
            return "error ClassNotFoundException | IOException e";          
        }           
        return "success";
    }

but I got the following exception:
SEVERE: El Servlet.service() para el servlet [Murachi] en el contexto con ruta [/Murachi] lanzó la excepción [eu.europa.ec.markt.dss.exception.DSSException: java.io.FileNotFoundException: File '/tmp/murachi/a52e340a-2d27-4b29-8b4c-4c4d7226fcaa.bdoc' does not exist] con causa raíz java.io.FileNotFoundException: File '/tmp/murachi/a52e340a-2d27-4b29-8b4c-4c4d7226fcaa.bdoc' does not exist at eu.europa.ec.markt.dss.DSSUtils.openInputStream(DSSUtils.java:1575) at eu.europa.ec.markt.dss.DSSUtils.toInputStream(DSSUtils.java:1430) at eu.europa.ec.markt.dss.signature.FileDocument.openStream(FileDocument.java:72) at eu.europa.ec.markt.dss.signature.FileDocument.save(FileDocument.java:106) at org.digidoc4j.impl.BDocContainer.save(BDocContainer.java:574) ...

It appears that it is not possible to save a container after deserializing it. Is this an invalid use of serialize and deserialize functions? I tried to follow this example. Any comment?

Best regards

@kristiu

This comment has been minimized.

Show comment
Hide comment
@kristiu

kristiu Aug 18, 2015

Hi Antonio, hope you are well too.

The reason for having the same SigningTime values in different signatures in your case is that when the signature's XML structure is created then the contents of the SigningTime XML element are taken from a signingDate variable (BdocContainer.dssSignatureParameters.bLevelParams.signingDate), the variable is initialized only once. Initialization is done when a new BDocContainer object is created (via the org.digidoc4j.impl.BDocContainer.initASiC() method).
As this variable is connected with the Container object then if you reuse the same Container object, you also reuse the same SigningTime value for all the signatures that you add to the container. Note that this also applies to other signature properties, e.g. SignatureProductionPlace and ClaimedRoles.

We are working on improving the design of the library, but currently, the solution for you could be to use different Container objects for each signature, e.g. write the container to an output stream, read in again and then add the next signature.

kristiu commented Aug 18, 2015

Hi Antonio, hope you are well too.

The reason for having the same SigningTime values in different signatures in your case is that when the signature's XML structure is created then the contents of the SigningTime XML element are taken from a signingDate variable (BdocContainer.dssSignatureParameters.bLevelParams.signingDate), the variable is initialized only once. Initialization is done when a new BDocContainer object is created (via the org.digidoc4j.impl.BDocContainer.initASiC() method).
As this variable is connected with the Container object then if you reuse the same Container object, you also reuse the same SigningTime value for all the signatures that you add to the container. Note that this also applies to other signature properties, e.g. SignatureProductionPlace and ClaimedRoles.

We are working on improving the design of the library, but currently, the solution for you could be to use different Container objects for each signature, e.g. write the container to an output stream, read in again and then add the next signature.

@kristiu

This comment has been minimized.

Show comment
Hide comment
@kristiu

kristiu Aug 18, 2015

About the serialization issue: does the sample application in SerializeExample
work?

kristiu commented Aug 18, 2015

About the serialization issue: does the sample application in SerializeExample
work?

@antonioaraujob

This comment has been minimized.

Show comment
Hide comment
@antonioaraujob

antonioaraujob Aug 19, 2015

Dear kristiu,
thank you very much for your comments.

I understand the problem I have with BDOC signatures with same xades:SigningTime. Your recommendation is writing the container to an output stream, reading in again and then adding the next signature.

Could you please give me a basic example of this?

On the other hand, I could test the sample application SerializeExample and it worked fine.

This example creates a new container, adds a DataFile, signs the container and
saves the container to disk.

I did a couple of tests:

i) saving the container without signing it. This throws an exception:

Exception in thread "main" Not implemented yet
    at org.digidoc4j.impl.BDocContainer.documentMustBeInitializedCheck(BDocContainer.java:593)
    at org.digidoc4j.impl.BDocContainer.save(BDocContainer.java:573)
    at SerializableExample.deserializer(SerializableExample.java:58)
    at SerializableExample.main(SerializableExample.java:14)

So it is not possible to save a BDOC container with a DataFile but without signing it (signedDocument == null).

ii) In the SerializeExample the BDocContainer.save() function calls InMemoryDocument.save() internally because of the container was created previously, so it can save the file correctly.

However, when I deserialize a BDocContainer (/tmp/murachi/a52e340a-2d27-4b29-8b4c-4c4d7226fcaa-serialized.bin with a DataFile and signature) and then I just try to use BDocContainer.save() this function calls FileDocument.save(). This last function tries to use the /tmp/murachi/a52e340a-2d27-4b29-8b4c-4c4d7226fcaa.bdocfile but this file does not exist (note that I only have the serialized file not the container). This is the code:

private static void deserializer() throws IOException, ClassNotFoundException {
    FileInputStream fileIn = new FileInputStream("/tmp/murachi/a52e340a-2d27-4b29-8b4c-4c4d7226fcaa-serialized.bin");
    ObjectInputStream in = new ObjectInputStream(fileIn);
    Container container = (Container) in.readObject();        
    System.out.println("numero de firmas antes : "+ Integer.toString(container.getSignatures().size()));
    container.save("/tmp/SerializeExample.bdoc");
    in.close();
    fileIn.close(); 
  }

The code throws this exception:

Exception in thread "main" eu.europa.ec.markt.dss.exception.DSSException: java.io.FileNotFoundException: File '/tmp/murachi/a52e340a-2d27-4b29-8b4c-4c4d7226fcaa.bdoc' does not exist
    at eu.europa.ec.markt.dss.DSSUtils.toInputStream(DSSUtils.java:1433)
    at eu.europa.ec.markt.dss.signature.FileDocument.openStream(FileDocument.java:72)
    at eu.europa.ec.markt.dss.signature.FileDocument.save(FileDocument.java:106)
    at org.digidoc4j.impl.BDocContainer.save(BDocContainer.java:574)
    at SerializableExample.deserializer(SerializableExample.java:58)
    at SerializableExample.main(SerializableExample.java:14)
Caused by: java.io.FileNotFoundException: File '/tmp/murachi/a52e340a-2d27-4b29-8b4c-4c4d7226fcaa.bdoc' does not exist
    at eu.europa.ec.markt.dss.DSSUtils.openInputStream(DSSUtils.java:1575)
    at eu.europa.ec.markt.dss.DSSUtils.toInputStream(DSSUtils.java:1430)

Could you please let me know how to avoid this?. I really appreciate your comments.

Best regards

antonioaraujob commented Aug 19, 2015

Dear kristiu,
thank you very much for your comments.

I understand the problem I have with BDOC signatures with same xades:SigningTime. Your recommendation is writing the container to an output stream, reading in again and then adding the next signature.

Could you please give me a basic example of this?

On the other hand, I could test the sample application SerializeExample and it worked fine.

This example creates a new container, adds a DataFile, signs the container and
saves the container to disk.

I did a couple of tests:

i) saving the container without signing it. This throws an exception:

Exception in thread "main" Not implemented yet
    at org.digidoc4j.impl.BDocContainer.documentMustBeInitializedCheck(BDocContainer.java:593)
    at org.digidoc4j.impl.BDocContainer.save(BDocContainer.java:573)
    at SerializableExample.deserializer(SerializableExample.java:58)
    at SerializableExample.main(SerializableExample.java:14)

So it is not possible to save a BDOC container with a DataFile but without signing it (signedDocument == null).

ii) In the SerializeExample the BDocContainer.save() function calls InMemoryDocument.save() internally because of the container was created previously, so it can save the file correctly.

However, when I deserialize a BDocContainer (/tmp/murachi/a52e340a-2d27-4b29-8b4c-4c4d7226fcaa-serialized.bin with a DataFile and signature) and then I just try to use BDocContainer.save() this function calls FileDocument.save(). This last function tries to use the /tmp/murachi/a52e340a-2d27-4b29-8b4c-4c4d7226fcaa.bdocfile but this file does not exist (note that I only have the serialized file not the container). This is the code:

private static void deserializer() throws IOException, ClassNotFoundException {
    FileInputStream fileIn = new FileInputStream("/tmp/murachi/a52e340a-2d27-4b29-8b4c-4c4d7226fcaa-serialized.bin");
    ObjectInputStream in = new ObjectInputStream(fileIn);
    Container container = (Container) in.readObject();        
    System.out.println("numero de firmas antes : "+ Integer.toString(container.getSignatures().size()));
    container.save("/tmp/SerializeExample.bdoc");
    in.close();
    fileIn.close(); 
  }

The code throws this exception:

Exception in thread "main" eu.europa.ec.markt.dss.exception.DSSException: java.io.FileNotFoundException: File '/tmp/murachi/a52e340a-2d27-4b29-8b4c-4c4d7226fcaa.bdoc' does not exist
    at eu.europa.ec.markt.dss.DSSUtils.toInputStream(DSSUtils.java:1433)
    at eu.europa.ec.markt.dss.signature.FileDocument.openStream(FileDocument.java:72)
    at eu.europa.ec.markt.dss.signature.FileDocument.save(FileDocument.java:106)
    at org.digidoc4j.impl.BDocContainer.save(BDocContainer.java:574)
    at SerializableExample.deserializer(SerializableExample.java:58)
    at SerializableExample.main(SerializableExample.java:14)
Caused by: java.io.FileNotFoundException: File '/tmp/murachi/a52e340a-2d27-4b29-8b4c-4c4d7226fcaa.bdoc' does not exist
    at eu.europa.ec.markt.dss.DSSUtils.openInputStream(DSSUtils.java:1575)
    at eu.europa.ec.markt.dss.DSSUtils.toInputStream(DSSUtils.java:1430)

Could you please let me know how to avoid this?. I really appreciate your comments.

Best regards

@kristiu

This comment has been minimized.

Show comment
Hide comment
@kristiu

kristiu Aug 21, 2015

Dear Antonio,

i) The solution could be to use two slightly different deserialization methods during the signature creation process.

When you do the two-step signing:

  • deserialize the container (previously created) - in this step, if the container already has any singatures added to it then re-initialize the object (write to output stream and read in again, the SigningTime and other signature parameters will be reset). If the container does not have any signatures yet (also meaning that Container.save() is not supported) then use the same object. For example:
  private static Container deserializer1() throws IOException,
      ClassNotFoundException {
    FileInputStream fileIn = new FileInputStream("container.bin");
    ObjectInputStream in = new ObjectInputStream(fileIn);
    Container container = (Container) in.readObject();
    in.close();
    fileIn.close();

    if (container.getSignatures().size() > 0) {
      ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
      container.save(byteOut);
      ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());

      Configuration configuration = initConfig(); // also need to re-initialize configuration settings
      Container container2 = Container.open(byteIn, configuration);

      byteOut.close();
      byteIn.close();
      return container2;
    } else {
      return container;
    }
  }
  • create signature parameters and signature production place
  • /.../
  • receive the signature
  • deserialize the container - in this step, you always need to reuse the previously serialized object, otherwise the signature parameters that you previously created will be lost and ( and the signature will not be valid).

ii) I couldn't reproduce the error situation. In my case, an InMemoryDocument is always used and exceptions do not occur. I tried with different DataFile sizes, enabled/disabled big file support, etc.
Please send the serialized container in case of which you get this error.

BR

kristiu commented Aug 21, 2015

Dear Antonio,

i) The solution could be to use two slightly different deserialization methods during the signature creation process.

When you do the two-step signing:

  • deserialize the container (previously created) - in this step, if the container already has any singatures added to it then re-initialize the object (write to output stream and read in again, the SigningTime and other signature parameters will be reset). If the container does not have any signatures yet (also meaning that Container.save() is not supported) then use the same object. For example:
  private static Container deserializer1() throws IOException,
      ClassNotFoundException {
    FileInputStream fileIn = new FileInputStream("container.bin");
    ObjectInputStream in = new ObjectInputStream(fileIn);
    Container container = (Container) in.readObject();
    in.close();
    fileIn.close();

    if (container.getSignatures().size() > 0) {
      ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
      container.save(byteOut);
      ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());

      Configuration configuration = initConfig(); // also need to re-initialize configuration settings
      Container container2 = Container.open(byteIn, configuration);

      byteOut.close();
      byteIn.close();
      return container2;
    } else {
      return container;
    }
  }
  • create signature parameters and signature production place
  • /.../
  • receive the signature
  • deserialize the container - in this step, you always need to reuse the previously serialized object, otherwise the signature parameters that you previously created will be lost and ( and the signature will not be valid).

ii) I couldn't reproduce the error situation. In my case, an InMemoryDocument is always used and exceptions do not occur. I tried with different DataFile sizes, enabled/disabled big file support, etc.
Please send the serialized container in case of which you get this error.

BR

@antonioaraujob

This comment has been minimized.

Show comment
Hide comment
@antonioaraujob

antonioaraujob Aug 24, 2015

Dear kristiu,
thank you very much for your comments and your time.

The deserialization method you proposed worked fine in the two-steps signing process. A container now keeps the signing time for each signature.

In ii) the serialized container was this. I have to say that I was using digidoc4j-0.2.9 version. After downloading the new version, digidoc4j-1.0, I could deserialize a BDOCContainer and then save it to disk successfully. InMemoryDocument is always used when I try to deserialize and save the container.

In spite of our work is documented in spanish, you could see our project here. We hope to use a basic service to create and sign BDOCs containers.

Thanks again and I really appreciate your help.

Best regards

antonioaraujob commented Aug 24, 2015

Dear kristiu,
thank you very much for your comments and your time.

The deserialization method you proposed worked fine in the two-steps signing process. A container now keeps the signing time for each signature.

In ii) the serialized container was this. I have to say that I was using digidoc4j-0.2.9 version. After downloading the new version, digidoc4j-1.0, I could deserialize a BDOCContainer and then save it to disk successfully. InMemoryDocument is always used when I try to deserialize and save the container.

In spite of our work is documented in spanish, you could see our project here. We hope to use a basic service to create and sign BDOCs containers.

Thanks again and I really appreciate your help.

Best regards

@kristiu kristiu closed this Aug 25, 2015

nostneji pushed a commit that referenced this issue May 4, 2017

Andrei Smirnov
#4 : Organized files under testFiles
Signed-off-by: Andrei <andrei.smirnov@cgi.com>

nostneji pushed a commit that referenced this issue May 4, 2017

Andrei Smirnov
#4 : Organized files under testFiles
Signed-off-by: Andrei <andrei.smirnov@cgi.com>

nostneji pushed a commit that referenced this issue May 4, 2017

jentsoni
Merge branch '4-dd4j-8' into 'master'
Resolve "DD4J-8"

Closes #4

See merge request !4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment