> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/core/digital-signature/dts.md).

# Add a DocTimeStamp signature on Server/Desktop

Set doctimestamp in PDF on Server/Desktop to add authenticity to the document.  Learn how to add trusted certifictae using WebViewer.

{% hint style="info" %}
**Requirements**

*These packages are required to use these features in production. Trial keys have unlimited access to all features*

<a href="https://apryse.com/capabilities#DigitalSignature" class="button primary">Package: Digital Signature</a><a href="https://showcase.apryse.com/digital-signatures" class="button primary">Live demo</a>
{% endhint %}

## Adding Trusted Certificate

When providing trusted certificate(s) through the `VerificationOptions.AddTrustedCertificate` method, ensure that it is the root certificate corresponding to the chain used by the timestamp authority to sign the timestamp token.

Check your Certificate Authority's website for a list of root certificates they have publicly available, and choose the root certificate corresponding to the set of certificates that have been signed by that root certificate for your usage.

To add a DocTimeStamp signature:

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
using (PDFDoc doc = new PDFDoc(in_docpath))
{
	DigitalSignatureField doctimestamp_signature_field = doc.CreateDigitalSignatureField();
	TimestampingConfiguration tst_config = new TimestampingConfiguration("URL_to_timestamp_authority");
	VerificationOptions opts = new VerificationOptions(VerificationOptions.SignatureVerificationSecurityLevel.e_compatibility_and_archiving);
	/* It is necessary to add to the VerificationOptions a trusted root certificate corresponding to 
	the chain used by the timestamp authority to sign the timestamp token, in order for the timestamp
	response to be verifiable during DocTimeStamp signing. */
	opts.AddTrustedCertificate(in_trusted_cert_path);
	/* By default, we only check online for revocation of certificates using the newer and lighter 
	OCSP protocol as opposed to CRL, due to lower resource usage and greater reliability. However, 
	it may be necessary to enable online CRL revocation checking in order to verify some timestamps
	(i.e. those that do not have an OCSP responder URL for all non-trusted certificates). */
	opts.EnableOnlineCRLRevocationChecking(true);

	SignatureWidget widgetAnnot = SignatureWidget.Create(doc, new Rect(0, 100, 200, 150), doctimestamp_signature_field);
	doc.GetPage(1).AnnotPushBack(widgetAnnot);
	Obj widgetObj = widgetAnnot.GetSDFObj();

	// (OPTIONAL) Add an appearance to the signature field.
	Image img = Image.Create(doc, in_appearance_img_path);
	widgetAnnot.CreateSignatureAppearance(img);

	Console.WriteLine("Testing timestamping configuration.");
	TimestampingTestResult config_result = tst_config.TestConfiguration(opts);
	if (config_result.GetStatus())
	{
		Console.WriteLine("Success: timestamping configuration usable. Attempting to timestamp.");
	}
	else
	{
		// Print details of timestamping failure.
		Console.WriteLine(config_result.GetString());
		if (config_result.HasResponseVerificationResult())
		{
			EmbeddedTimestampVerificationResult tst_result = config_result.GetResponseVerificationResult();
			Console.WriteLine("CMS digest status: %s\n", tst_result.GetCMSDigestStatusAsString());
			Console.WriteLine("Message digest status: %s\n", tst_result.GetMessageImprintDigestStatusAsString());
			Console.WriteLine("Trust status: %s\n", tst_result.GetTrustStatusAsString());
		}
		return false;
	}

	doctimestamp_signature_field.TimestampOnNextSave(tst_config, opts);

	// Save/signing throws if timestamping fails.
	doc.Save(in_outpath, SDFDoc.SaveOptions.e_incremental);
}
```

{% endcode %}
{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
PDFDoc doc(in_docpath);
DigitalSignatureField doctimestamp_signature_field = doc.CreateDigitalSignatureField();
TimestampingConfiguration tst_config("URL_to_timestamp_authority");
VerificationOptions opts(VerificationOptions::e_compatibility_and_archiving);
/* It is necessary to add to the VerificationOptions a trusted root certificate corresponding to 
the chain used by the timestamp authority to sign the timestamp token, in order for the timestamp
response to be verifiable during DocTimeStamp signing. */
opts.AddTrustedCertificate(in_trusted_cert_path);
/* By default, we only check online for revocation of certificates using the newer and lighter 
OCSP protocol as opposed to CRL, due to lower resource usage and greater reliability. However, 
it may be necessary to enable online CRL revocation checking in order to verify some timestamps
(i.e. those that do not have an OCSP responder URL for all non-trusted certificates). */
opts.EnableOnlineCRLRevocationChecking(true);

Annots::SignatureWidget widgetAnnot = Annots::SignatureWidget::Create(doc, Rect(0, 100, 200, 150), doctimestamp_signature_field);
doc.GetPage(1).AnnotPushBack(widgetAnnot);

// (OPTIONAL) Add an appearance to the signature field.
PDF::Image img = PDF::Image::Create(doc, in_appearance_img_path);
widgetAnnot.CreateSignatureAppearance(img);

puts("Testing timestamping configuration.");
const TimestampingTestResult config_result(tst_config.TestConfiguration(opts));
if (config_result.GetStatus())
{
	puts("Success: timestamping configuration usable. Attempting to timestamp.");
}
else
{
	// Print details of timestamping failure.
	puts(config_result.GetString().ConvertToUtf8().c_str());
	if (config_result.HasResponseVerificationResult())
	{
		EmbeddedTimestampVerificationResult tst_result(config_result.GetResponseVerificationResult());
		printf("CMS digest status: %s\n", tst_result.GetCMSDigestStatusAsString().ConvertToUtf8().c_str());
		printf("Message digest status: %s\n", tst_result.GetMessageImprintDigestStatusAsString().ConvertToUtf8().c_str());
		printf("Trust status: %s\n", tst_result.GetTrustStatusAsString().ConvertToUtf8().c_str());
	}
	return false;
}

doctimestamp_signature_field.TimestampOnNextSave(tst_config, opts);

// Save/signing throws if timestamping fails.
doc.Save(in_outpath, SDFDoc::e_incremental, 0);
```

{% endcode %}
{% endtab %}

{% tab title="Go" %}
{% code lineNumbers="true" %}

```go
doc := NewPDFDoc(inDocpath)
doctimestampSignatureField := doc.CreateDigitalSignatureField()
tstConfig := NewTimestampingConfiguration("URL_to_timestamp_authority")
opts := NewVerificationOptions(VerificationOptionsE_compatibility_and_archiving)
//   It is necessary to add to the VerificationOptions a trusted root certificate corresponding to 
//   the chain used by the timestamp authority to sign the timestamp token, in order for the timestamp
//   response to be verifiable during DocTimeStamp signing. It is also necessary in the context of this 
//   function to do this for the later LTV section, because one needs to be able to verify the DocTimeStamp 
//   in order to enable LTV for it, and we re-use the VerificationOptions opts object in that part.

opts.AddTrustedCertificate(inTrustedCertPath)
//       By default, we only check online for revocation of certificates using the newer and lighter 
//   OCSP protocol as opposed to CRL, due to lower resource usage and greater reliability. However, 
//   it may be necessary to enable online CRL revocation checking in order to verify some timestamps
//   (i.e. those that do not have an OCSP responder URL for all non-trusted certificates).

opts.EnableOnlineCRLRevocationChecking(true)

widgetAnnot := SignatureWidgetCreate(doc, NewRect(0.0, 100.0, 200.0, 150.0), doctimestampSignatureField)
doc.GetPage(1).AnnotPushBack(widgetAnnot)

// (OPTIONAL) Add an appearance to the signature field.
img := ImageCreate(doc.GetSDFDoc(), inAppearanceImgPath)
widgetAnnot.CreateSignatureAppearance(img)

fmt.Println("Testing timestamping configuration.")
configResult := tstConfig.TestConfiguration(opts)
if configResult.GetStatus(){
		fmt.Println("Success: timestamping configuration usable. Attempting to timestamp.")
}else{
		// Print details of timestamping failure.
		fmt.Println(configResult.GetString())
		if configResult.HasResponseVerificationResult(){
				tstResult := configResult.GetResponseVerificationResult()
				fmt.Println("CMS digest status: "+ tstResult.GetCMSDigestStatusAsString())
				fmt.Println("Message digest status: " + tstResult.GetMessageImprintDigestStatusAsString())
				fmt.Println("Trust status: " + tstResult.GetTrustStatusAsString())
		}
		return false
}

doctimestampSignatureField.TimestampOnNextSave(tstConfig, opts)

// Save/signing throws if timestamping fails.
doc.Save(inOutpath, uint(SDFDocE_incremental))
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
PDFDoc doc = new PDFDoc(in_docpath); 
DigitalSignatureField doctimestamp_signature_field = doc.createDigitalSignatureField();  
TimestampingConfiguration tst_config = new TimestampingConfiguration("URL_to_timestamp_authority");
VerificationOptions opts = new VerificationOptions(VerificationOptions.SecurityLevel.e_compatibility_and_archiving); 
/* It is necessary to add to the VerificationOptions a trusted root certificate corresponding to 
the chain used by the timestamp authority to sign the timestamp token, in order for the timestamp
response to be verifiable during DocTimeStamp signing. */
opts.addTrustedCertificate(in_trusted_cert_path);
/* By default, we only check online for revocation of certificates using the newer and lighter 
OCSP protocol as opposed to CRL, due to lower resource usage and greater reliability. However, 
it may be necessary to enable online CRL revocation checking in order to verify some timestamps
(i.e. those that do not have an OCSP responder URL for all non-trusted certificates). */
opts.enableOnlineCRLRevocationChecking(true);

SignatureWidget widgetAnnot = SignatureWidget.create(doc, new Rect(0, 100, 200, 150), doctimestamp_signature_field);
doc.getPage(1).annotPushBack(widgetAnnot);

// (OPTIONAL) Add an appearance to the signature field.
Image img = Image.create(doc, in_appearance_img_path);
widgetAnnot.createSignatureAppearance(img);

System.out.println("Testing timestamping configuration.");
TimestampingTestResult config_result = tst_config.testConfiguration(opts);
if (config_result.getStatus())
{
	System.out.println("Success: timestamping configuration usable. Attempting to timestamp.");
}
else
{
	// Print details of timestamping failure.
	System.out.println(config_result.getString());
	if (config_result.hasResponseVerificationResult())
	{
		EmbeddedTimestampVerificationResult tst_result = config_result.getResponseVerificationResult();
		System.out.println(String.format("CMS digest status: %s", tst_result.getCMSDigestStatusAsString()));
		System.out.println(String.format("Message digest status: %s", tst_result.getMessageImprintDigestStatusAsString()));
		System.out.println(String.format("Trust status: %s", tst_result.getTrustStatusAsString()));
	}
	return false;
}

doctimestamp_signature_field.timestampOnNextSave(tst_config, opts);

// Save/signing throws if timestamping fails.
doc.save(in_outpath, SDFDoc.SaveMode.INCREMENTAL, null);
```

{% endcode %}
{% endtab %}

{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
async function main() {
	const doc = await PDFNet.PDFDoc.createFromFilePath(in_docpath);
	doc.initSecurityHandler();
	const doctimestamp_signature_field = await doc.createDigitalSignatureField();
	const tst_config = await PDFNet.TimestampingConfiguration.createFromURL("URL_to_timestamp_authority");
	const opts = await PDFNet.VerificationOptions.create(PDFNet.VerificationOptions.SecurityLevel.e_compatibility_and_archiving);
	/* It is necessary to add to the VerificationOptions a trusted root certificate corresponding to 
	the chain used by the timestamp authority to sign the timestamp token, in order for the timestamp
	response to be verifiable during DocTimeStamp signing. */
	await opts.addTrustedCertificateUString(in_trusted_cert_path);
	/* By default, we only check online for revocation of certificates using the newer and lighter 
	OCSP protocol as opposed to CRL, due to lower resource usage and greater reliability. However, 
	it may be necessary to enable online CRL revocation checking in order to verify some timestamps
	(i.e. those that do not have an OCSP responder URL for all non-trusted certificates). */
	await opts.enableOnlineCRLRevocationChecking(true);

	const widgetAnnot = await PDFNet.SignatureWidget.createWithDigitalSignatureField(doc, new PDFNet.Rect(0, 100, 200, 150), doctimestamp_signature_field);
	await (await doc.getPage(1)).annotPushBack(widgetAnnot);

	// (OPTIONAL) Add an appearance to the signature field.
	const img = await PDFNet.Image.createFromFile(doc, in_appearance_img_path);
	await widgetAnnot.createSignatureAppearance(img);

	console.log('Testing timestamping configuration.');
	const config_result = await tst_config.testConfiguration(opts);
	if (await config_result.getStatus()) {
		console.log('Success: timestamping configuration usable. Attempting to timestamp.');
	} else {
		// Print details of timestamping failure.
		console.log(await config_result.getString());
		if (await config_result.hasResponseVerificationResult()) {
			const tst_result = await config_result.getResponseVerificationResult();
			console.log('CMS digest status: ' + await tst_result.getCMSDigestStatusAsString());
			console.log('Message digest status: ' + await tst_result.getMessageImprintDigestStatusAsString());
			console.log('Trust status: ' + await tst_result.getTrustStatusAsString());
		}
		return false;
	}

	await doctimestamp_signature_field.timestampOnNextSave(tst_config, opts);

	// Save/signing throws if timestamping fails.
	await doc.save(in_outpath, PDFNet.SDFDoc.SaveOptions.e_incremental);
}
PDFNet.runWithCleanup(main);
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
val doc = PDFDoc(in_docpath)
val doctimestamp_signature_field = doc.createDigitalSignatureField()
val tst_config = TimestampingConfiguration("URL_to_timestamp_authority")
val opts = VerificationOptions(VerificationOptions.SecurityLevel.e_compatibility_and_archiving)
/* It is necessary to add to the VerificationOptions a trusted root certificate corresponding to
the chain used by the timestamp authority to sign the timestamp token, in order for the timestamp
response to be verifiable during DocTimeStamp signing. */
opts.addTrustedCertificate(in_trusted_cert_path)
/* By default, we only check online for revocation of certificates using the newer and lighter
OCSP protocol as opposed to CRL, due to lower resource usage and greater reliability. However,
it may be necessary to enable online CRL revocation checking in order to verify some timestamps
(i.e. those that do not have an OCSP responder URL for all non-trusted certificates). */
opts.enableOnlineCRLRevocationChecking(true)
val widgetAnnot = SignatureWidget.create(doc, Rect(0.0, 100.0, 200.0, 150.0), doctimestamp_signature_field)
doc.getPage(1).annotPushBack(widgetAnnot)

// (OPTIONAL) Add an appearance to the signature field.
val img = Image.create(doc, in_appearance_img_path)
widgetAnnot.createSignatureAppearance(img)
println("Testing timestamping configuration.")
val config_result = tst_config.testConfiguration(opts)
if (config_result.status) {
    println("Success: timestamping configuration usable. Attempting to timestamp.")
} else {
    // Print details of timestamping failure.
    println(config_result.string)
    if (config_result.hasResponseVerificationResult()) {
        val tst_result = config_result.responseVerificationResult
        println(String.format("CMS digest status: %s", tst_result.cmsDigestStatusAsString))
        println(String.format("Message digest status: %s", tst_result.messageImprintDigestStatusAsString))
        println(String.format("Trust status: %s", tst_result.trustStatusAsString))
    }
    return false
}
doctimestamp_signature_field.timestampOnNextSave(tst_config, opts)

// Save/signing throws if timestamping fails.
doc.save(in_outpath, SDFDoc.SaveMode.INCREMENTAL, null)
```

{% endcode %}
{% endtab %}

{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objc
PTPDFDoc* doc = [[PTPDFDoc alloc] initWithFilepath: in_docpath];
PTDigitalSignatureField* doctimestamp_signature_field = [doc CreateDigitalSignatureField: @""];
PTTimestampingConfiguration* tst_config = [[PTTimestampingConfiguration alloc] initWithIn_url: @"URL_to_timestamp_authority"];
PTVerificationOptions* opts = [[PTVerificationOptions alloc] initWithLevel:e_ptcompatibility_and_archiving];

/* It is necessary to add to the VerificationOptions a trusted root certificate corresponding to 
the chain used by the timestamp authority to sign the timestamp token, in order for the timestamp
response to be verifiable during DocTimeStamp signing. */
[ opts AddTrustedCertificateWithFilePath: in_trusted_cert_path];
/* By default, we only check online for revocation of certificates using the newer and lighter 
OCSP protocol as opposed to CRL, due to lower resource usage and greater reliability. However, 
it may be necessary to enable online CRL revocation checking in order to verify some timestamps
(i.e. those that do not have an OCSP responder URL for all non-trusted certificates). */
[ opts EnableOnlineCRLRevocationChecking: YES];

PTSignatureWidget* widgetAnnot = [PTSignatureWidget CreateWithDigitalSignatureField: doc pos: [[PTPDFRect alloc] initWithX1: 0 y1: 100 x2: 200 y2: 150] field: doctimestamp_signature_field];
[[doc GetPage: 1] AnnotPushBack: widgetAnnot];

// (OPTIONAL) Add an appearance to the signature field.
PTImage* img = [PTImage CreateWithFile: [doc GetSDFDoc] filename: in_appearance_img_path encoder_hints: [[PTObj alloc]init]];

[widgetAnnot CreateSignatureAppearance: img];

NSLog(@"Testing timestamping configuration.");
PTTimestampingTestResult* config_result = [tst_config TestConfiguration:opts];
if([ config_result GetStatus])
{
	NSLog(@"Success: timestamping configuration usable. Attempting to timestamp.");
}
else
{
	// Print details of timestamping failure.
	NSLog(@"%@", [config_result GetString]);
	if ([config_result HasResponseVerificationResult])
	{
		PTEmbeddedTimestampVerificationResult* tst_result = [config_result GetResponseVerificationResult];
		NSLog(@"CMS digest status: %@\n", [tst_result GetCMSDigestStatusAsString]);
		NSLog(@"Message digest status: %@\n", [tst_result GetMessageImprintDigestStatusAsString]);
		NSLog(@"Trust status: %@\n", [tst_result GetTrustStatusAsString]);
	}
	return NO;
}

[doctimestamp_signature_field TimestampOnNextSave: tst_config in_timestamp_response_verification_options: opts];

// Save/signing throws if timestamping fails.
[doc SaveToFile: in_outpath flags: e_ptincremental];
```

{% endcode %}
{% endtab %}

{% tab title="PHP" %}
{% code lineNumbers="true" %}

```php
$doc = new PDFDoc($in_docpath);
$doctimestamp_signature_field = $doc->CreateDigitalSignatureField();
$tst_config = new TimestampingConfiguration("URL_to_timestamp_authority");
$opts = new VerificationOptions(VerificationOptions::e_compatibility_and_archiving);
/* It is necessary to add to the VerificationOptions a trusted root certificate corresponding to 
the chain used by the timestamp authority to sign the timestamp token, in order for the timestamp
response to be verifiable during DocTimeStamp signing. */
$opts->AddTrustedCertificate($in_trusted_cert_path);
/* By default, we only check online for revocation of certificates using the newer and lighter 
OCSP protocol as opposed to CRL, due to lower resource usage and greater reliability. However, 
it may be necessary to enable online CRL revocation checking in order to verify some timestamps
(i.e. those that do not have an OCSP responder URL for all non-trusted certificates). */
$opts->EnableOnlineCRLRevocationChecking(true);

$widgetAnnot = SignatureWidget::Create($doc, new Rect(0.0, 100.0, 200.0, 150.0), $doctimestamp_signature_field);
$doc->GetPage(1)->AnnotPushBack($widgetAnnot);

// (OPTIONAL) Add an appearance to the signature field.
$img = Image::Create($doc->GetSDFDoc(), $in_appearance_img_path);
$widgetAnnot->CreateSignatureAppearance($img);

echo(nl2br('Testing timestamping configuration.'.PHP_EOL));
$config_result = $tst_config->TestConfiguration($opts);
if ($config_result->GetStatus())
{
	echo(nl2br('Success: timestamping configuration usable. Attempting to timestamp.'.PHP_EOL));
}
else
{
	// Print details of timestamping failure.
	echo(nl2br($config_result->GetString().PHP_EOL));
	if ($config_result->HasResponseVerificationResult())
	{
		$tst_result = $config_result->GetResponseVerificationResult();
		echo(nl2br('CMS digest status: '.$tst_result->GetCMSDigestStatusAsString().PHP_EOL));
		echo(nl2br('Message digest status: '.$tst_result->GetMessageImprintDigestStatusAsString().PHP_EOL));
		echo(nl2br('Trust status: '.$tst_result->GetTrustStatusAsString().PHP_EOL));
	}
	return false;
}

$doctimestamp_signature_field->TimestampOnNextSave($tst_config, $opts);

// Save/signing throws if timestamping fails.
$doc->Save($in_outpath, SDFDoc::e_incremental);
```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code lineNumbers="true" %}

```python
doctimestamp_signature_field = doc.CreateDigitalSignatureField()
# It is necessary to add to the VerificationOptions a trusted root certificate corresponding to 
# the chain used by the timestamp authority to sign the timestamp token, in order for the timestamp
# response to be verifiable during DocTimeStamp signing. 
opts.AddTrustedCertificate(in_trusted_cert_path)
# By default, we only check online for revocation of certificates using the newer and lighter 
# OCSP protocol as opposed to CRL, due to lower resource usage and greater reliability. However, 
# it may be necessary to enable online CRL revocation checking in order to verify some timestamps
# (i.e. those that do not have an OCSP responder URL for all non-trusted certificates).
opts.EnableOnlineCRLRevocationChecking(True)

widgetAnnot = SignatureWidget.Create(doc, Rect(0.0, 100.0, 200.0, 150.0), doctimestamp_signature_field)
doc.GetPage(1).AnnotPushBack(widgetAnnot)

# (OPTIONAL) Add an appearance to the signature field.
img = Image.Create(doc.GetSDFDoc(), in_appearance_img_path)
widgetAnnot.CreateSignatureAppearance(img)

print('Testing timestamping configuration.')
config_result = tst_config.TestConfiguration(opts)
if config_result.GetStatus():
	print('Success: timestamping configuration usable. Attempting to timestamp.')
else:
	# Print details of timestamping failure.
	print(config_result.GetString())
	if config_result.HasResponseVerificationResult():
		tst_result = config_result.GetResponseVerificationResult()
		print('CMS digest status: '+ tst_result.GetCMSDigestStatusAsString())
		print('Message digest status: ' + tst_result.GetMessageImprintDigestStatusAsString())
		print('Trust status: ' + tst_result.GetTrustStatusAsString())
	return False


doctimestamp_signature_field.TimestampOnNextSave(tst_config, opts)

# Save/signing throws if timestamping fails.
doc.Save(in_outpath, SDFDoc.e_incremental)
```

{% endcode %}
{% endtab %}

{% tab title="Ruby" %}
{% code lineNumbers="true" %}

```ruby
doc = PDFDoc.new(in_docpath);
doctimestamp_signature_field = doc.CreateDigitalSignatureField();
tst_config = TimestampingConfiguration.new("URL_to_timestamp_authority");
opts = VerificationOptions.new(VerificationOptions::E_compatibility_and_archiving);
# It is necessary to add to the VerificationOptions a trusted root certificate corresponding to 
# the chain used by the timestamp authority to sign the timestamp token, in order for the timestamp
# response to be verifiable during DocTimeStamp signing.

	opts.AddTrustedCertificate(in_trusted_cert_path);
# By default, we only check online for revocation of certificates using the newer and lighter 
# OCSP protocol as opposed to CRL, due to lower resource usage and greater reliability. However, 
# it may be necessary to enable online CRL revocation checking in order to verify some timestamps
# (i.e. those that do not have an OCSP responder URL for all non-trusted certificates).

opts.EnableOnlineCRLRevocationChecking(true);

widgetAnnot = SignatureWidget.Create(doc, Rect.new(0.0, 100.0, 200.0, 150.0), doctimestamp_signature_field);
doc.GetPage(1).AnnotPushBack(widgetAnnot);

# (OPTIONAL) Add an appearance to the signature field.
img = Image.Create(doc.GetSDFDoc(), in_appearance_img_path);
widgetAnnot.CreateSignatureAppearance(img);

puts('Testing timestamping configuration.');
config_result = tst_config.TestConfiguration(opts);
if (config_result.GetStatus())
	puts('Success: timestamping configuration usable. Attempting to timestamp.');
else
	# Print details of timestamping failure.
	puts(config_result.GetString());
	if config_result.HasResponseVerificationResult()
		tst_result = config_result.GetResponseVerificationResult();
		puts('CMS digest status: '+ tst_result.GetCMSDigestStatusAsString());
		puts('Message digest status: ' + tst_result.GetMessageImprintDigestStatusAsString());
		puts('Trust status: ' + tst_result.GetTrustStatusAsString());
	end
	return false;
end

doctimestamp_signature_field.TimestampOnNextSave(tst_config, opts);

# Save/signing throws if timestamping fails.
doc.Save(in_outpath, SDFDoc::E_incremental);
```

{% endcode %}
{% endtab %}

{% tab title="VB" %}
{% code lineNumbers="true" %}

```vb
Using doc As PDFDoc = New PDFDoc(in_docpath)
	Dim doctimestamp_signature_field As DigitalSignatureField = doc.CreateDigitalSignatureField()
	Dim tst_config As TimestampingConfiguration = New TimestampingConfiguration("URL_to_timestamp_authority")
	Dim opts As VerificationOptions = New VerificationOptions(VerificationOptions.SignatureVerificationSecurityLevel.e_compatibility_and_archiving)
	
	opts.AddTrustedCertificate(in_trusted_cert_path)
	opts.EnableOnlineCRLRevocationChecking(True)
	Dim widgetAnnot As SignatureWidget = SignatureWidget.Create(doc, New Rect(0, 100, 200, 150), doctimestamp_signature_field)
	doc.GetPage(1).AnnotPushBack(widgetAnnot)
	Dim widgetObj As Obj = widgetAnnot.GetSDFObj()
	Dim img As Image = Image.Create(doc, in_appearance_img_path)
	widgetAnnot.CreateSignatureAppearance(img)
	Console.WriteLine("Testing timestamping configuration.")
	Dim config_result As TimestampingTestResult = tst_config.TestConfiguration(opts)

	If config_result.GetStatus() Then
		Console.WriteLine("Success: timestamping configuration usable. Attempting to timestamp.")
	Else
		Console.WriteLine(config_result.GetString())

		If config_result.HasResponseVerificationResult() Then
			Dim tst_result As EmbeddedTimestampVerificationResult = config_result.GetResponseVerificationResult()
			Console.WriteLine("CMS digest status: %s" & vbLf, tst_result.GetCMSDigestStatusAsString())
			Console.WriteLine("Message digest status: %s" & vbLf, tst_result.GetMessageImprintDigestStatusAsString())
			Console.WriteLine("Trust status: %s" & vbLf, tst_result.GetTrustStatusAsString())
		End If

		Return False
	End If

	doctimestamp_signature_field.TimestampOnNextSave(tst_config, opts)
	doc.Save(in_outpath, SDFDoc.SaveOptions.e_incremental)
End Using
```

{% endcode %}
{% endtab %}
{% endtabs %}

[Digital signatures](/core/get-started/samples/digitalsignaturestest.md) Full code sample which demonstrates using the digital signature API to digitally sign, certify, and/or verify PDF documents. Code sample is available in C++, C#, Java, Python, Go, PHP, Ruby & VB.

## About DocTimeStamp (DTS)

If it is important that a signature in a document have a timestamp that is verifiable with a third-party entity (i.e. Certificate Authority), then performing DTS would allow verification of when the document was signed. A Certificate Authority that hosts a timestamp server publicly is known as a [`Timestamp Authority (TSA)`](#timestamp-authority-tsa). Timestamping a signature can be achieved by sending a hash of the signature data to the TSA's timestamping server ( which is what is achieved with the above code sample). If the request is deemed valid, the server will combine the hash provided by the client and an authoritative date-time of timestamping, signed by a private key from the Certificate Authority. The [`Timestamp Token`](#timestamp-token) is then recorded into the document alongside the signature.

If future viewers that open the timestamped and signed document have the same TSA as part of their trust list, then the viewer's PDF viewing application will acknowledge that the signature has been verifiably timestamped.

## Definition of Terms

### Chain of Trust

A chain of certificates, starting with a `root certificate`, an `intermediate certificate` and an `end-entity certificate`, forming a linked path of validation and verification from a trust anchor (i.e. Certificate Authority) down to an `end-entity certificate`. As the name implies, a root certificate is analogous to the root of a tree, where each branch of the tree is it's own chain of trust.

Note that "chain of trust" is also sometimes known as a "trust path"

### Root Certificate

A root certificate is the top-most certificate in a `chain of trust`/`trust path`, the private key of which is used to "sign" other certificates. All certificates signed by the root certificate inherit the trustworthiness of the root certificate.

### Intermediate Certificate

Act as a middle-man between the protected `root certificate` and the `end-entity certificate`. Note there is always at least one `intermediate certificate` in a chain of trust, but there could be more than one.

### End-entity Certificate

The last in a chain of trust (i.e. a leaf node of the tree) that identifies either a business, a website, or a person. With respect to digital signatures, identifying the individuals who signed a document is where the trust worthiness of the chain(s) (i.e. where the `end-entity certificates` originated from) is important.

### Timestamp Authority (TSA)

A trusted third party acting as the authoratative entity providing a timestamp, via a timestamp token. Clients who contact a TSA server will create a hashed value (as a unique identifier of the data or file that needs to be timestamped), and send the hashed value to the TSA.

More information about TSAs can be read about in the Time-Stamp Protocol ([RFC 3161](https://tools.ietf.org/html/rfc3161/)) industry standard.

### Timestamp Token

A combination of the hash provided by the client and the authoritative date-time of timestamping, digitally signed with the TSA's private key, that is received by the client, and recorded into the document.

Future client applications who open the document will use the TSA's public key to

1. Authenticate the TSA
2. Re-calculate the hash of the original data

This new hash is compared to the originally created hash, and if any changes to the data has been made since the timestamp was originally created, then a warning should be raised by the client application.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/core/digital-signature/dts.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
