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;