Discuss this help topic in SecureBlackbox Forum

Sign document asynchronously

The topic of asynchronous signing is discussed in the corresponding how-to. Below you will find a complex example of asynchronous signing of an Office document.

C#:


void EmulateDistribSigningOffice(string SourceFileName, string TempFileName, string DestFileName,
	string StateFileName, string StateOutFileName, string CertFileName, string CertPassword,
	bool BinarySignature)
{
	Stream F, OutF;
	TElOfficeDocument Document;
	TElOfficeCustomSignatureHandler Handler;
	TElX509Certificate Cert, PubCert;

	TElDCAsyncState State = null;
	TElDCStandardServer Server;
	TElDCX509SignOperationHandler SigHandler;

	// create a certificate for signing
	PubCert = new TElX509Certificate(null);
	Cert = new TElX509Certificate(null);
	try
	{
		Cert.LoadFromFileAuto(CertFileName, CertPassword);
		Cert.Clone(PubCert, false);
	}
	finally
	{
		Cert.Dispose();
	}

	// Make a copy of the document, as we will need to save a partially signed document
	File.Copy(SourceFileName, TempFileName, false);
	Document = new TElOfficeDocument(null);
	try
	{
		// open the document
		Document.Open(TempFileName);

		// check if we can sign it
		if (!Document.Signable)
			throw new Exception("Failed to sign document");

		// create a proper signature handler
		// and initiate the asynchronous signing
		if (Document.DocumentFormat == TSBOfficeDocumentFormat.dfBinary)
		{
			if (BinarySignature)
			{
				Handler = new TElOfficeBinaryCryptoAPISignatureHandler(null);
				Document.AddSignature(Handler, true);

				State = ((TElOfficeBinaryCryptoAPISignatureHandler) Handler).InitiateAsyncSign(PubCert);
			}
			else
			{
				Handler = new TElOfficeBinaryXMLSignatureHandler(null);
				Document.AddSignature(Handler, true);

				State = ((TElOfficeBinaryXMLSignatureHandler) Handler).InitiateAsyncSign(PubCert);
			}
		}
		else
		if (Document.DocumentFormat == TSBOfficeDocumentFormat.dfOpenXML)
		{
			Handler = new TElOfficeOpenXMLSignatureHandler(null);
			Document.AddSignature(Handler, true);

			// sign something
			((TElOfficeOpenXMLSignatureHandler) Handler).AddDocument;

			State = ((TElOfficeOpenXMLSignatureHandler) Handler).InitiateAsyncSign(PubCert);
		}
		else
		if (Document.DocumentFormat == TSBOfficeDocumentFormat.dfOpenXPS)
		{
			Handler = new TElOfficeOpenXPSSignatureHandler(null);
			Document.AddSignature(Handler, true);

			// sign something
			((TElOfficeOpenXPSSignatureHandler) Handler).AddDocument();

			State = ((TElOfficeOpenXPSSignatureHandler) Handler).InitiateAsyncSign(PubCert);
		}
		else
		if (Document.DocumentFormat == TSBOfficeDocumentFormat.dfOpenDocument)
		{
			Handler = new TElOpenOfficeSignatureHandler(null);
			Document.AddSignature(Handler, true);

			// sign something
			((TElOpenOfficeSignatureHandler) Handler).AddDocument();

			State = ((TElOpenOfficeSignatureHandler) Handler).InitiateAsyncSign(PubCert);
		};
	}
	finally
	{
		Document.Dispose();
	}
	PubCert.Dispose();

	// save the obtained state to file for debug purposes
	F = new FileStream(StateFileName, FileMode.Create);
	try
	{
		State.SaveToStream(F, null);
	}
	finally
	{
		F.Close();
	}

	State = null;

	// Process the state in a signature server
	// In most cases this would be a browser applet,
	// but a class in your module would also work
	SigHandler = new TElDCX509SignOperationHandler();
	SigHandler.CertStorage = new TElMemoryCertStorage(null);
	F = new FileStream(CertFileName, FileMode.OpenRead);
	try
	{
		SigHandler.CertStorage.LoadFromStreamPFX(F, CertPassword);
	}
	finally
	{
		F.Close();
	}

	// In this block we usually load the state on the signature server side.
	// As this sample emulates distributed signing, the same file is used
	// to save the state by the signature client
	// and to load it on the signature server.
	Server = new TElDCStandardServer();
	Server.AddOperationHandler(SigHandler);
	F = new FileStream(StateFileName, FileMode.OpenRead);
	try
	{
		OutF = new FileStream(StateOutFileName, FileMode.Create);
		try
		{
			Server.Process(F, OutF, null, null);
		}
		finally
		{
			OutF.Close();
		}
	}
	finally
	{
		F.Close();
	}

	// Finalize the signature on the side which holds the document
	State = new TElDCAsyncState();
	F = new FileStream(StateOutFileName, FileMode.OpenRead);
	try
	{
		State.LoadFromStream(F, null);
	}
	finally
	{
		F.Close();
	}

	// restore the haslf-signed document from the temporary storage
	// and complete the signing procedure
	File.Copy(TempFileName, DestFileName, false);
	Document = new TElOfficeDocument(null);
	try
	{
		Document.Open(DestFileName);
		Document.CompleteAsyncSign(Document.get_SignatureHandlers(Document.SignatureHandlerCount - 1), State);
	}
	finally
	{
		Document.Dispose();
	}

	State = null;
};
Delphi:

procedure EmulateDistribSigningOffice(const SourceFileName, TempFileName, DestFileName,
  StateFileName, StateOutFileName,
  CertFileName, CertPassword : string;
  BinarySignature : Boolean = False);
var
  F, OutF : TStream;
  Document : TElOfficeDocument;
  Handler : TElOfficeCustomSignatureHandler;
  Cert, PubCert : TElX509Certificate;

  State : TElDCAsyncState;
  Server : TElDCStandardServer;
  SigHandler : TElDCX509SignOperationHandler;
begin
  State := nil;

  // create a certificate for signing
  PubCert := TElX509Certificate.Create(nil);
  Cert := TElX509Certificate.Create(nil);
  try
    Cert.LoadFromFileAuto(CertFileName, CertPassword);
    Cert.Clone(PubCert, False);
  finally
    FreeAndNil(Cert);
  end;

  // Make a copy of the document, as we will need to save a partially signed document
  CopyFile(PChar(SourceFileName), PChar(TempFileName), False);
  Document := TElOfficeDocument.Create(nil);
  try
	// open the document
    Document.Open(TempFileName);

	// check if we can sign it
    if not Document.Signable then
      raise Exception.Create('Failed to sign document');

	// create a proper signature handler
	// and initiate the asynchronous signing
    if Document.DocumentFormat = dfBinary then
    begin
      if BinarySignature then
      begin
        Handler := TElOfficeBinaryCryptoAPISignatureHandler.Create(nil);
        Document.AddSignature(Handler, true);

        State := TElOfficeBinaryCryptoAPISignatureHandler(Handler).InitiateAsyncSign(PubCert);
      end
      else
      begin
        Handler := TElOfficeBinaryXMLSignatureHandler.Create(nil);
        Document.AddSignature(Handler, true);

        State := TElOfficeBinaryXMLSignatureHandler(Handler).InitiateAsyncSign(PubCert);
      end;
    end
    else
    if Document.DocumentFormat = dfOpenXML then
    begin
      Handler := TElOfficeOpenXMLSignatureHandler.Create(nil);
      Document.AddSignature(Handler, true);

      // sign something
      TElOfficeOpenXMLSignatureHandler(Handler).AddDocument;

      State := TElOfficeOpenXMLSignatureHandler(Handler).InitiateAsyncSign(PubCert);
    end
    else if Document.DocumentFormat = dfOpenXPS then
    begin
      Handler := TElOfficeOpenXPSSignatureHandler.Create(nil);
      Document.AddSignature(Handler, true);

      // sign something
      TElOfficeOpenXPSSignatureHandler(Handler).AddDocument();

      State := TElOfficeOpenXPSSignatureHandler(Handler).InitiateAsyncSign(PubCert);
    end
    else if Document.DocumentFormat = dfOpenDocument then
    begin
      Handler := TElOpenOfficeSignatureHandler.Create(nil);
      Document.AddSignature(Handler, true);

      // sign something
      TElOpenOfficeSignatureHandler(Handler).AddDocument();

      State := TElOpenOfficeSignatureHandler(Handler).InitiateAsyncSign(PubCert);
    end;

  finally
    FreeAndNil(Document);
  end;
  FreeAndNil(PubCert);

  // save the obtained state to file for debug purposes
  F := TFileStream.Create(StateFileName, fmCreate);
  try
    State.SaveToStream(F, nil);
  finally
    FreeAndNil(F);
  end;

  FreeAndNil(State);

  // Process the state in a signature server
  // In most cases this would be a browser applet,
  // but a class in your module would also work
  SigHandler := TElDCX509SignOperationHandler.Create();
  SigHandler.CertStorage := TElMemoryCertStorage.Create(nil);
  F := TFileStream.Create(CertFileName, fmOpenRead);
  try
    SigHandler.CertStorage.LoadFromStreamPFX(F, CertPassword);
  finally
    FreeAndNil(F);
  end;

  Server := TElDCStandardServer.Create();
  Server.AddOperationHandler(SigHandler);
  F := TFileStream.Create(StateFileName, fmOpenRead);
  try
    OutF := TFileStream.Create(StateOutFileName, fmCreate);
    try
      Server.Process(F, OutF, nil, nil);
    finally
      FreeAndNil(OutF);
    end;
  finally
    FreeAndNil(F);
  end;

  // Finalize the signature on the side which holds the document
  State := TElDCAsyncState.Create();
  F := TFileStream.Create(StateOutFileName, fmOpenRead);
  try
    State.LoadFromStream(F, nil);
  finally
    FreeAndNil(F);
  end;

  // restore the haslf-signed document from the temporary storage
  // and complete the signing procedure
  CopyFile(PChar(TempFileName), PChar(DestFileName), False);
  Document := TElOfficeDocument.Create(nil);
  try
    Document.Open(DestFileName);
    Document.CompleteAsyncSign(Document.SignatureHandlers[Document.SignatureHandlerCount - 1], State);
  finally
    FreeAndNil(Document);
  end;

  FreeAndNil(State);
end;

How To articles about common Office tasks

Discuss this help topic in SecureBlackbox Forum