Example use of digital signature verification with certificate chain validation.
#include "tools.h"
void print_verify_help() {
printf("Usage: verify -f [signed PDF file] [options]\n");
printf("Options:\n");
printf(" -f [file] Signed PDF file to verify (required)\n");
printf(" -c [certs] Trusted certificate store directory (optional, uses system defaults if not specified)\n");
printf(" -l [license] License file (optional)\n");
printf(" --skip-certificate-validation Skip X509 certificate chain validation (insecure, for testing only)\n");
printf(" --allow-weak-algorithms Allow weak cryptographic algorithms (MD5, SHA-1, RSA < 2048 bits)\n");
printf(" --check-signing-time Validate certificate at signing time instead of current time\n");
}
int process_verify(int argc, char *argv[]) {
int arg_counter = 0;
for (arg_counter = 0; arg_counter < argc; ++arg_counter) {
if (strcmp(argv[arg_counter], "-f") == 0 && (arg_counter + 1 < argc)) {
pdf_file = argv[arg_counter + 1];
arg_counter++;
} else if (strcmp(argv[arg_counter], "-c") == 0 && (arg_counter + 1 < argc)) {
certs_path = argv[arg_counter + 1];
arg_counter++;
} else if (strcmp(argv[arg_counter], "-l") == 0 && (arg_counter + 1 < argc)) {
license_file = argv[arg_counter + 1];
arg_counter++;
} else if (strcmp(argv[arg_counter], "--skip-certificate-validation") == 0) {
} else if (strcmp(argv[arg_counter], "--allow-weak-algorithms") == 0) {
} else if (strcmp(argv[arg_counter], "--check-signing-time") == 0) {
} else {
print_verify_help();
return VANILLAPDF_TOOLS_ERROR_INVALID_PARAMETERS;
}
}
if (pdf_file == NULL) {
printf("Error: PDF file is required\n");
print_verify_help();
return VANILLAPDF_TOOLS_ERROR_INVALID_PARAMETERS;
}
if (license_file != NULL) {
RETURN_ERROR_IF_NOT_SUCCESS(LicenseInfo_SetLicenseFile(license_file));
}
printf("Opening PDF file: %s\n", pdf_file);
RETURN_ERROR_IF_NOT_SUCCESS(File_Open(pdf_file, &file));
RETURN_ERROR_IF_NOT_SUCCESS(Document_OpenFile(file, &document));
error_type catalog_result = Document_GetCatalog(document, &catalog);
printf("Error: Failed to get document catalog (not a valid PDF?)\n");
return VANILLAPDF_TOOLS_ERROR_FAILURE;
}
error_type acroform_result = Catalog_GetAcroForm(catalog, &acro_form);
printf("Error: No AcroForm found in PDF (document has no form fields)\n");
Catalog_Release(catalog);
Document_Release(document);
File_Release(file);
return VANILLAPDF_TOOLS_ERROR_FAILURE;
}
printf("Error: Failed to get AcroForm\n");
return VANILLAPDF_TOOLS_ERROR_FAILURE;
}
error_type fields_result = InteractiveForm_GetFields(acro_form, &fields);
printf("Error: Failed to get form fields\n");
InteractiveForm_Release(acro_form);
Catalog_Release(catalog);
Document_Release(document);
File_Release(file);
return VANILLAPDF_TOOLS_ERROR_FAILURE;
}
RETURN_ERROR_IF_NOT_SUCCESS(FieldCollection_GetSize(fields, &field_count));
if (field_count == 0) {
printf("Error: No form fields found in PDF\n");
FieldCollection_Release(fields);
InteractiveForm_Release(acro_form);
Catalog_Release(catalog);
Document_Release(document);
File_Release(file);
return VANILLAPDF_TOOLS_ERROR_FAILURE;
}
printf("Found %llu form field(s), searching for signature fields...\n", (unsigned long long) field_count);
RETURN_ERROR_IF_NOT_SUCCESS(TrustedCertificateStore_Create(&trust_store));
if (certs_path != NULL) {
printf("Loading trusted certificates from: %s\n", certs_path);
RETURN_ERROR_IF_NOT_SUCCESS(TrustedCertificateStore_LoadFromDirectory(trust_store, certs_path));
} else {
printf("Loading system default trusted certificates\n");
RETURN_ERROR_IF_NOT_SUCCESS(TrustedCertificateStore_LoadSystemDefaults(trust_store));
}
RETURN_ERROR_IF_NOT_SUCCESS(SignatureVerificationSettings_Create(&settings));
if (skip_certificate_validation) {
printf("WARNING: Skipping certificate chain validation (insecure)\n");
RETURN_ERROR_IF_NOT_SUCCESS(SignatureVerificationSettings_SetSkipCertificateValidation(settings,
VANILLAPDF_RV_TRUE));
}
if (allow_weak_algorithms) {
printf("Allowing weak cryptographic algorithms\n");
RETURN_ERROR_IF_NOT_SUCCESS(SignatureVerificationSettings_SetAllowWeakAlgorithmsFlag(settings,
VANILLAPDF_RV_TRUE));
}
if (check_signing_time) {
printf("Checking certificate validity at signing time\n");
RETURN_ERROR_IF_NOT_SUCCESS(SignatureVerificationSettings_SetCheckSigningTimeFlag(settings,
VANILLAPDF_RV_TRUE));
}
int overall_result = VANILLAPDF_TOOLS_ERROR_SUCCESS;
for (
size_type i = 0; i < field_count; i++) {
field = NULL;
sig_field = NULL;
digital_signature = NULL;
result = NULL;
error_type field_result = FieldCollection_At(fields, i, &field);
printf("Warning: Failed to get field at index %llu\n", (unsigned long long) i);
continue;
}
error_type sig_result = SignatureField_FromField(field, &sig_field);
Field_Release(field);
continue;
}
error_type value_result = SignatureField_GetValue(sig_field, &digital_signature);
printf("Warning: Signature field at index %llu has no value\n", (unsigned long long) i);
SignatureField_Release(sig_field);
Field_Release(field);
continue;
}
signature_count++;
printf("\n=== Verifying Signature #%llu ===\n", (unsigned long long) signature_count);
RETURN_ERROR_IF_NOT_SUCCESS(SignatureVerificationResult_GetStatus(result, &status));
RETURN_ERROR_IF_NOT_SUCCESS(SignatureVerificationResult_IsSignatureValid(result, &is_signature_valid));
RETURN_ERROR_IF_NOT_SUCCESS(SignatureVerificationResult_IsDocumentIntact(result, &is_document_intact));
RETURN_ERROR_IF_NOT_SUCCESS(SignatureVerificationResult_IsCertificateTrusted(result, &is_cert_trusted));
RETURN_ERROR_IF_NOT_SUCCESS(SignatureVerificationResult_GetSignerCommonName(result, &signer_name));
RETURN_ERROR_IF_NOT_SUCCESS(SignatureVerificationResult_GetMessage(result, &message_buffer));
printf("Status: ");
switch (status) {
printf("VALID\n");
break;
printf("INVALID\n");
break;
printf("CERTIFICATE EXPIRED\n");
break;
printf("CERTIFICATE NOT YET VALID\n");
break;
printf("CERTIFICATE REVOKED\n");
break;
printf("CERTIFICATE UNTRUSTED\n");
break;
printf("WEAK CRYPTOGRAPHIC ALGORITHM\n");
break;
default:
printf("UNKNOWN (%d)\n", status);
break;
}
printf("Signature Valid: %s\n", is_signature_valid ? "Yes" : "No");
printf("Document Intact: %s\n", is_document_intact ? "Yes" : "No");
printf("Certificate Trusted: %s\n", is_cert_trusted ? "Yes" : "No");
if (signer_name != NULL) {
RETURN_ERROR_IF_NOT_SUCCESS(Buffer_GetData(signer_name, &name_data, &name_size));
if (name_size > 0) {
printf("Signer: %s\n", name_data);
}
}
if (message_buffer != NULL) {
RETURN_ERROR_IF_NOT_SUCCESS(Buffer_GetData(message_buffer, &message_data, &message_size));
if (message_size > 0) {
printf("Message: %s\n", message_data);
}
}
overall_result = VANILLAPDF_TOOLS_ERROR_FAILURE;
}
if (message_buffer) Buffer_Release(message_buffer);
if (signer_name) Buffer_Release(signer_name);
if (result) SignatureVerificationResult_Release(result);
if (digital_signature) DigitalSignature_Release(digital_signature);
if (sig_field) SignatureField_Release(sig_field);
if (field) Field_Release(field);
}
printf("\n============================\n");
if (signature_count == 0) {
printf("No signature fields found in PDF\n");
overall_result = VANILLAPDF_TOOLS_ERROR_FAILURE;
} else {
printf("Verified %llu signature(s)\n", (unsigned long long) signature_count);
}
printf("============================\n\n");
if (settings) SignatureVerificationSettings_Release(settings);
if (trust_store) TrustedCertificateStore_Release(trust_store);
if (fields) FieldCollection_Release(fields);
if (acro_form) InteractiveForm_Release(acro_form);
if (catalog) Catalog_Release(catalog);
if (document) Document_Release(document);
if (file) File_Release(file);
return overall_result;
}
error_type CALLING_CONVENTION DigitalSignatureExtensions_Verify(DigitalSignatureHandle *signature, DocumentHandle *document, TrustedCertificateStoreHandle *trusted_store, SignatureVerificationSettingsHandle *settings, SignatureVerificationResultHandle **result)
Verify the digital signature in a PDF document.
Represents memory stored data.
The root of a document's object hierarchy.
Represents document's authenticated digital signature.
Represents high-level file access handle.
Collection of FieldHandle.
Base class for all fields.
Represents low-level file access handle.
A signature field (PDF 1.3) is a form field that contains a digital signature.
Result of signature verification operation.
Configuration settings for signature verification.
Collection of trusted certificates for signature verification.
const boolean_type VANILLAPDF_RV_TRUE
Represents the boolean true value.
const boolean_type VANILLAPDF_RV_FALSE
Represents the boolean false value.
const error_type VANILLAPDF_ERROR_OBJECT_MISSING
A dependent object was not found.
const error_type VANILLAPDF_ERROR_SUCCESS
Indicates that the operation completed successfully.
uint32_t error_type
This is return value type of all API functions.
Definition c_types.h:25
int8_t boolean_type
Boolean type supported in C.
Definition c_types.h:31
uint32_t size_type
Size type defined in standard library.
Definition c_types.h:62
const char * string_type
C-Style string.
Definition c_types.h:82
SignatureVerificationStatusType
Overall status of signature verification.
Definition c_signature_verifier.h:37
@ SignatureStatus_WeakAlgorithm
Definition c_signature_verifier.h:46
@ SignatureStatus_CertificateRevoked
Definition c_signature_verifier.h:43
@ SignatureStatus_CertificateExpired
Definition c_signature_verifier.h:41
@ SignatureStatus_Invalid
Definition c_signature_verifier.h:40
@ SignatureStatus_CertificateUntrusted
Definition c_signature_verifier.h:44
@ SignatureStatus_Valid
Definition c_signature_verifier.h:39
@ SignatureStatus_CertificateNotYetValid
Definition c_signature_verifier.h:42