签名 (Signature)
PDF 签名功能用于创建和签署 PDF 文档的数字签名,旨在保护文档内容的安全性,防止恶意篡改。通过数字签名,接收者可以确信收到的文档来源于签名者,并且文档内容在传输过程中保持完整性,未经任何修改。
福昕 PDF SDK 提供了一系列 API,用于实现以下签名相关操作:
- 创建数字签名
- 验证签名的有效性
- 删除现有的数字签名
- 获取和设置数字签名的属性
- 显示签名
- 自定义签名表单域的外观
默认签名回调函数
福昕 PDF SDK 内置了默认的签名回调函数,支持以下两种标准的签名过滤器 (filter) 和子过滤器 (subfilter):
filter: Adobe.PPKLite
subfilter: adbe.pkcs7.detached
filter: Adobe.PPKLite
subfilter: adbe.pkcs7.sha1
提示:
- 如果您的签名需求符合以上任一过滤器和子过滤器的组合,您可以直接使用 SDK 提供的 API 进行 PDF 文档的签名和签名有效性验证,无需注册自定义的回调函数,从而简化了开发流程。
对 PDF 文档进行签名
c++
#include "include/pdf/annots/fs_annot.h"
#include "include/common/fs_image.h"
#include "include/pdf/fs_pdfdoc.h"
#include "include/pdf/fs_pdfpage.h"
#include "include/pdf/fs_signature.h"
using namespace foxit;
using namespace foxit::common;
using foxit::common::Library;
using namespace pdf;
using namespace objects;
using namespace file;
// AdobePPKLiteSignature
const char* filter = "Adobe.PPKLite";
const char* sub_filter = "adbe.pkcs7.detached";
if (!use_default) {
InitializeOpenssl();
sub_filter = "adbe.pkcs7.sha1";
SignatureCallbackImpl* sig_callback = new SignatureCallbackImpl(sub_filter);
Library::RegisterSignatureCallback(filter, sub_filter, sig_callback);
}
printf("Use signature callback object for filter \"%s\" and sub-filter \"%s\"\r\n",
filter, sub_filter);
PDFPage pdf_page = pdf_doc.GetPage(0);
// Add a new signature to the first page.
Signature new_signature = AddSiganture(pdf_page, sub_filter);
// Set filter and subfilter for the new signature.
new_signature.SetFilter(filter);
new_signature.SetSubFilter(sub_filter);
bool is_signed = new_signature.IsSigned();
uint32 sig_state = new_signature.GetState();
printf("[Before signing] Signed?:%s\t State:%s\r\n",
is_signed? "true" : "false",
TransformSignatureStateToString(sig_state).c_str());
// Sign the new signature.
WString signed_pdf_path = output_directory + L"signed_newsignature.pdf";
if (use_default)
signed_pdf_path = output_directory + L"signed_newsignature_default_handler.pdf";
WString cert_file_path = input_path + L"foxit_all.pfx";
WString cert_file_password = L"123456";
// Cert file path will be passed back to application through callback function FSSignatureCallback::Sign().
// In this demo, the cert file path will be used for signing in callback function FSSignatureCallback::Sign().
new_signature.StartSign((const wchar_t*)cert_file_path, cert_file_password,
Signature::e_DigestSHA1, (const wchar_t*)signed_pdf_path, NULL, NULL);
printf("[Sign] Finished!\r\n");
is_signed = new_signature.IsSigned();
sig_state = new_signature.GetState();
printf("[After signing] Signed?:%s\tState:%s\r\n",
is_signed? "true" : "false",
TransformSignatureStateToString(sig_state).c_str());
// Open the signed document and verify the newly added signature (which is the last one).
printf("Signed PDF file: %s\r\n", (const char*)String::FromUnicode(signed_pdf_path));
PDFDoc signed_pdf_doc((const wchar_t*)signed_pdf_path);
ErrorCode error_code = signed_pdf_doc.Load(NULL);
if (foxit::e_ErrSuccess !=error_code ) {
printf("Fail to open the signed PDF file.\r\n");
return;
}
// Get the last signature which is just added and signed.
int sig_count = signed_pdf_doc.GetSignatureCount();
Signature signed_signature = signed_pdf_doc.GetSignature(sig_count-1);
// Verify the signature.
signed_signature.StartVerify(NULL, NULL);
printf("[Verify] Finished!\r\n");
is_signed = signed_signature.IsSigned();
sig_state = signed_signature.GetState();
printf("[After verifying] Signed?:%s\tState:%s\r\n",
is_signed? "true" : "false",
TransformSignatureStateToString(sig_state).c_str());
C
#include "include/fs_basictypes_c.h"
#include "include/fs_annot_c.h"
#include "include/fs_image_c.h"
#include "include/fs_pdfdoc_c.h"
#include "include/fs_pdfpage_c.h"
#include "include/fs_signature_c.h"
// AdobePPKLiteSignature
const char* filter = "Adobe.PPKLite";
const char* sub_filter = "adbe.pkcs7.detached";
if (!use_default) {
InitializeOpenssl();
sub_filter = "adbe.pkcs7.sha1";
FSSignatureCallback* sig_callback = (FSSignatureCallback*)malloc(sizeof(FSSignatureCallback));
sig_callback->user_data = sig_callback;
sig_callback->StartCalcDigest = gStartCalcDigest;
sig_callback->ContinueCalcDigest = gContinueCalcDigest;
sig_callback->GetDigest = gGetDigest;
sig_callback->Sign = gSign;
sig_callback->Sign0 = gSign0;
sig_callback->VerifySigState = gVerifySigState;
sig_callback->IsNeedPadData = gIsNeedPadData;
sig_callback->CheckCertificateValidity = gCheckCertificateValidity;
FS_BOOL return_Callback;
FSDK_Library_RegisterSignatureCallback(filter, sub_filter, sig_callback, &return_Callback);
}
printf("Use signature callback object for filter \"%s\" and sub-filter \"%s\"\r\n",
filter, sub_filter);
FS_PDFPAGE_HANDLE pdf_page;
FSDK_PDFDoc_GetPage(pdf_doc, 0, &pdf_page);
// Add a new signature to the first page.
FS_SIGNATURE_HANDLE new_signature = AddSiganture(pdf_page, &sub_filter);
// Set filter and subfilter for the new signature.
FSDK_Signature_SetFilter(new_signature, filter);
FSDK_Signature_SetSubFilter(new_signature, sub_filter);
FS_BOOL is_signed;
FSDK_Signature_IsSigned(new_signature, &is_signed);
FS_UINT32 sig_state;
char sig_state_str[256] = { 0 };
FSDK_Signature_GetState(new_signature, &sig_state);
printf("[Before signing] Signed?:%s\t State:%s\r\n",
is_signed? "true" : "false",
TransformSignatureStateToString(sig_state_str, 256, sig_state));
// Sign the new signature.
wchar_t signed_pdf_path[MAX_FILE_PATH];
swprintf_s(signed_pdf_path, MAX_FILE_PATH, L"%lssigned_newsignature.pdf",output_directory);
if (use_default)
swprintf_s(signed_pdf_path, MAX_FILE_PATH, L"%lssigned_newsignature_default_handler.pdf ",output_directory);
wchar_t cert_file_path[MAX_FILE_PATH];
swprintf_s(cert_file_path, MAX_FILE_PATH, L"%lsfoxit_all.pfx", input_path);
const wchar_t* cert_file_password = L"123456";
// Cert file path will be passed back to application through callback function FSSignatureCallback::Sign().
// In this demo, the cert file path will be used for signing in callback function FSSignatureCallback::Sign().
FS_PROGRESSIVE_HANDLE progressive;
FSDK_Signature_StartSign(new_signature, cert_file_path, cert_file_password, e_FSDigestSHA1, signed_pdf_path, NULL, NULL, &progressive);
printf("[Sign] Finished!\r\n");
FSDK_Signature_IsSigned(new_signature, &is_signed);
FSDK_Signature_GetState(new_signature, &sig_state);
printf("[After signing] Signed?:%s\tState:%s\r\n",
is_signed? "true" : "false",
TransformSignatureStateToString(sig_state_str, 256, sig_state));
// Open the signed document and verify the newly added signature (which is the last one).
wprintf(L"Signed PDF file: %ls\r\n", signed_pdf_path);
FS_PDFDOC_HANDLE signed_pdf_doc;
FSDK_PDFDoc_Create0(signed_pdf_path, &signed_pdf_doc);
FSErrorCode error_code = FSDK_PDFDoc_Load(signed_pdf_doc, NULL);
if (e_FSErrSuccess !=error_code ) {
FSDK_PDFDoc_Release(signed_pdf_doc);
printf("Fail to open the signed PDF file.\r\n");
return;
}
// Get the last signature which is just added and signed.
int sig_count;
FSDK_PDFDoc_GetSignatureCount(signed_pdf_doc, &sig_count);
FS_SIGNATURE_HANDLE signed_signature;
FSDK_PDFDoc_GetSignature(signed_pdf_doc, sig_count - 1, &signed_signature);
// Verify the signature.
FS_PROGRESSIVE_HANDLE progressive2;
FSDK_Signature_StartVerify(signed_signature,NULL ,NULL, &progressive2);
printf("[Verify] Finished!\r\n");
FSDK_Signature_IsSigned(signed_signature, &is_signed);
FSDK_Signature_GetState(signed_signature, &sig_state);
printf("[After verifying] Signed?:%s\tState:%s\r\n",
is_signed? "true" : "false",
TransformSignatureStateToString(sig_state_str, 256, sig_state));
java
import com.foxit.sdk.pdf.*;
...
String filter = "Adobe.PPKLite";
String sub_filter = "adbe.pkcs7.detached";
PDFPage pdf_page = pdf_doc.getPage(0);
// Add a new signature to first page.
com.foxit.sdk.pdf.Signature new_signature = AddSiganture(pdf_page, sub_filter);
// Set filter and subfilter for the new signature.
new_signature.setFilter(filter);
new_signature.setSubFilter(sub_filter);
boolean is_signed = new_signature.isSigned();
int sig_state = new_signature.getState();
String signed_pdf_path = output_directory + "signed_newsignature.pdf";
String cert_file_path = input_path + "foxit_all.pfx";
String cert_file_password = "123456";
// Cert file path will be passed back to application through callback function SignatureCallback::Sign().
// In this demo, the cert file path will be used for signing in callback function SignatureCallback::Sign().
new_signature.startSign(cert_file_path, cert_file_password.getBytes(), e_DigestSHA1, signed_pdf_path, null, null);
...
py
import sys
import site
if sys.version_info.major == 2:
_PYTHON2_ = True
else:
_PYTHON2_ = False
if _PYTHON2_:
#replace with the python2 lib path
site.addsitedir('../../../')
from FoxitPDFSDKPython2 import *
else:
from FoxitPDFSDKPython3 import *
…
filter = "Adobe.PPKLite"
sub_filter = "adbe.pkcs7.detached"
if not use_default:
sub_filter = "adbe.pkcs7.sha1"
sig_callback = SignatureCallbackImpl(sub_filter)
Library.RegisterSignatureCallback(filter, sub_filter, sig_callback)
print(
"Use signature callback object for filter \"{}\" and sub-filter \"{}\"\r\n"
.format(filter, sub_filter))
pdf_page = pdf_doc.GetPage(0)
# Add a new signature to first page.
new_signature = AddSiganture(pdf_page, sub_filter)
# Set filter and subfilter for the new signature.
new_signature.SetFilter(filter)
new_signature.SetSubFilter(sub_filter)
is_signed = new_signature.IsSigned()
sig_state = new_signature.GetState()
print("[Before signing] Signed?:{}\t State:{}\r\n".format(
"true" if is_signed else "false",
TransformSignatureStateToString(sig_state)))
# Sign the new signature.
signed_pdf_path = output_directory + "signed_newsignature.pdf"
if use_default:
signed_pdf_path = output_directory + "signed_newsignature_default_handle.pdf"
cert_file_path = input_path + "foxit_all.pfx"
cert_file_password = "123456"
# Cert file path will be passed back to application through callback function FSSignatureCallback.Sign().
# In this demo, the cert file path will be used for signing in callback function FSSignatureCallback.Sign().
new_signature.StartSign(cert_file_path, cert_file_password,
Signature.e_DigestSHA1, signed_pdf_path)
print("[Sign] Finished!\r\n")
is_signed = new_signature.IsSigned()
sig_state = new_signature.GetState()
print("[After signing] Signed?:{}\tState:{}\r\n".format(
"true" if is_signed else "false",
TransformSignatureStateToString(sig_state)))
# Open the signed document and verify the newly added signature (which is the last one).
print("Signed PDF file: {}\r\n".format(signed_pdf_path))
signed_pdf_doc = PDFDoc(signed_pdf_path)
error_code = signed_pdf_doc.Load("")
if e_ErrSuccess != error_code:
print("Fail to open the signed PDF file.\r\n")
return
# Get the last signature which is just added and signed.
sig_count = signed_pdf_doc.GetSignatureCount()
signed_signature = signed_pdf_doc.GetSignature(sig_count - 1)
# Verify the intergrity of signature.
signed_signature.StartVerify("", None)
print("[Verify] Finished!\r\n")
is_signed = signed_signature.IsSigned()
sig_state = signed_signature.GetState()
print("[After verifying] Signed?:{}\tState:{}\r\n".format(
"true" if is_signed else "false",
TransformSignatureStateToString(sig_state)))
objc
#include "FSPDFObjC.h"
...
NSString *filter = @"Adobe.PPKLite";
NSString *sub_filter = @"adbe.pkcs7.detached";
if (!use_default) {
InitializeOpenssl();
sub_filter = @"adbe.pkcs7.sha1";
SignatureCallback *sig_callback = [[SignatureCallback alloc] initWithSubFilter:sub_filter];
[FSLibrary registerSignatureCallback:filter sub_filter:sub_filter signature_callback:sig_callback];
}
[filter UTF8String], [sub_filter UTF8String]);
FSPDFPage *pdf_page = [pdf_doc getPage:0];
// Add a new signature to first page.
FSSignature *new_signature = AddSiganture(pdf_page, sub_filter);
// Set filter and subfilter for the new signature.
[new_signature setFilter:filter];
[new_signature setSubFilter:sub_filter];
// Sign the new signature.
NSString *signed_pdf_path = [output_directory stringByAppendingPathComponent:@"signed_newsignature.pdf"];
if (use_default)
signed_pdf_path = [output_directory stringByAppendingPathComponent:@"signed_newsignature_default_handler.pdf"];
NSString *cert_file_path = [input_path stringByAppendingPathComponent:@"foxit_all.pfx"];
NSString *cert_file_password = @"123456";
// Cert file path will be passed back to application through callback function FSSignatureCallback::Sign().
// In this demo, the cert file path will be used for signing in callback function FSSignatureCallback::Sign().
[new_signature startSign:cert_file_path cert_password:cert_file_password digest_algorithm:FSSignatureDigestSHA1 save_path:signed_pdf_path client_data:nil pause:nil];
// Open the signed document and verify the newly added signature (which is the last one).
FSPDFDoc *signed_pdf_doc = [[FSPDFDoc alloc] initWithPath:signed_pdf_path];
FSErrorCode error_code = [signed_pdf_doc load:nil];
if (FSErrSuccess != error_code) {
return;
}
// Get the last signature which is just added and signed.
int sig_count = [signed_pdf_doc getSignatureCount];
FSSignature *signed_signature = [signed_pdf_doc getSignature:sig_count - 1];
// Verify the signature.
[signed_signature startVerify:nil pause:nil];
...
js
const FSDK = require("@foxitsoftware/foxit-pdf-sdk-node");
…
let filter = "Adobe.PPKLite";
let sub_filter = "adbe.pkcs7.detached";
console.log("Use signature callback object for filter \"%s\" and sub-filter \"%s\"", filter, sub_filter);
let pdf_page = pdf_doc.GetPage(0);
// Add a new signature to first page.
let new_signature = AddSiganture(pdf_page, sub_filter);
// Set filter and subfilter for the new signature.
new_signature.SetFilter(filter);
new_signature.SetSubFilter(sub_filter);
let is_signed = new_signature.IsSigned();
let sig_state = new_signature.GetState();
console.log("[Before signing] Signed?:%s\t State:%s",is_signed? "true" : "false",
TransformSignatureStateToString(sig_state));
// Sign the new signature.
let signed_pdf_path = output_directory + "signed_newsignature_default_handler.pdf";
let cert_file_path = input_path + "foxit_all.pfx";
let cert_file_password = "123456";
// Cert file path will be passed back to application through callback function FSSignatureCallback::Sign().
// In this demo, the cert file path will be used for signing in callback function FSSignatureCallback::Sign().
new_signature.StartSign(cert_file_path, cert_file_password,
FSDK.Signature.e_DigestSHA1, signed_pdf_path, null, null);
console.log("[Sign] Finished!");
is_signed = new_signature.IsSigned();
sig_state = new_signature.GetState();
console.log("[After signing] Signed?:%s\tState:%s",is_signed? "true" : "false",
TransformSignatureStateToString(sig_state));
// Open the signed document and verify the newly added signature (which is the last one).
console.log("Signed PDF file: %s", signed_pdf_path);
let signed_pdf_doc = new FSDK.PDFDoc(signed_pdf_path);
error_code = signed_pdf_doc.Load("");
if (FSDK.e_ErrSuccess !=error_code ) {
console.log("Fail to open the signed PDF file.");
return;
}
// Get the last signature which is just added and signed.
let sig_count = signed_pdf_doc.GetSignatureCount();
let signed_signature = signed_pdf_doc.GetSignature(sig_count-1);
// Verify the intergrity of signature.
signed_signature.StartVerify(Buffer.alloc(0), null);
console.log("[Verify] Finished!");
is_signed = signed_signature.IsSigned();
sig_state = signed_signature.GetState();
console.log("[After verifying] Signed?:%s\tState:%s", is_signed? "true" : "false",
TransformSignatureStateToString(sig_state));
csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using foxit.common;
using foxit.pdf;
using foxit;
using foxit.pdf.annots;
using foxit.common.fxcrt;
using System.Runtime.InteropServices;
using foxit.pdf.interform;
static foxit.common.DateTime GetLocalDateTime()
{
System.DateTimeOffset rime = System.DateTimeOffset.Now;
foxit.common.DateTime datetime = new foxit.common.DateTime();
datetime.year = (UInt16)rime.Year;
datetime.month = (UInt16)rime.Month;
datetime.day = (ushort)rime.Day;
datetime.hour = (UInt16)rime.Hour;
datetime.minute = (UInt16)rime.Minute;
datetime.second = (UInt16)rime.Second;
datetime.utc_hour_offset = (short)rime.Offset.Hours;
datetime.utc_minute_offset = (ushort)rime.Offset.Minutes;
return datetime;
}
static Signature AddSiganture(PDFPage pdf_page, string sub_filter) {
float page_height = pdf_page.GetHeight();
float page_width = pdf_page.GetWidth();
RectF new_sig_rect = new RectF(0, (float)(page_height*0.9), (float)(page_width*0.4), page_height);
// Add a new signature to page.
Signature new_sig = pdf_page.AddSignature(new_sig_rect);
if (new_sig.IsEmpty()) return null;
// Set values for the new signature.
new_sig.SetKeyValue(Signature.KeyName.e_KeyNameSigner, "Foxit PDF SDK");
String new_value = String.Format("As a sample for subfilter \"{0}\"", sub_filter);
new_sig.SetKeyValue(Signature.KeyName.e_KeyNameReason, new_value);
new_sig.SetKeyValue(Signature.KeyName.e_KeyNameContactInfo, "support@foxitsoftware.com");
new_sig.SetKeyValue(Signature.KeyName.e_KeyNameDN, "CN=CN,MAIL=MAIL@MAIL.COM");
new_sig.SetKeyValue(Signature.KeyName.e_KeyNameLocation, "Fuzhou, China");
new_value = String.Format("As a sample for subfilter \"{0}\"", sub_filter);
new_sig.SetKeyValue(Signature.KeyName.e_KeyNameText, new_value);
foxit.common.DateTime sign_time = GetLocalDateTime();
new_sig.SetSignTime(sign_time);
String image_file_path = input_path + "FoxitLogo.jpg";
using (Image image = new Image(image_file_path))
{
new_sig.SetImage(image, 0);
// Set appearance flags to decide which content would be used in appearance.
int ap_flags = Convert.ToInt32(Signature.APFlags.e_APFlagLabel | Signature.APFlags.e_APFlagSigner |
Signature.APFlags.e_APFlagReason | Signature.APFlags.e_APFlagDN |
Signature.APFlags.e_APFlagLocation | Signature.APFlags.e_APFlagText |
Signature.APFlags.e_APFlagSigningTime | Signature.APFlags.e_APFlagBitmap);
new_sig.SetAppearanceFlags(ap_flags);
}
return new_sig;
}
static void AdobePPKLiteSignature(PDFDoc pdf_doc) {
string filter = "Adobe.PPKLite";
string sub_filter = "adbe.pkcs7.detached";
using (PDFPage pdf_page = pdf_doc.GetPage(0))
{
// Add a new signature to first page.
using (Signature new_signature = AddSiganture(pdf_page, sub_filter))
{
// Set filter and subfilter for the new signature.
new_signature.SetFilter(filter);
new_signature.SetSubFilter(sub_filter);
// Sign the new signature.
String signed_pdf_path = output_directory + "signed_newsignature.pdf";
String cert_file_path = input_path + "foxit_all.pfx";
byte[] cert_file_password = Encoding.ASCII.GetBytes("123456");
new_signature.StartSign(cert_file_path, cert_file_password,
Signature.DigestAlgorithm.e_DigestSHA1, signed_pdf_path, IntPtr.Zero, null);
Console.WriteLine("[Sign] Finished!");
}
}
}
static void Main(String[] args)
{
...
AdobePPKLiteSignature(pdf_doc);
...
}
实现签名的回调函数
c++
#include "include/pdf/annots/fs_annot.h"
#include "include/common/fs_image.h"
#include "include/pdf/fs_pdfdoc.h"
#include "include/pdf/fs_pdfpage.h"
#include "include/pdf/fs_signature.h"
using namespace foxit;
using namespace foxit::common;
using foxit::common::Library;
using namespace pdf;
using namespace objects;
using namespace file;
// Implementation of pdf::SignatureCallback
class SignatureCallbackImpl : public pdf::SignatureCallback {
public:
SignatureCallbackImpl(string subfilter)
: sub_filter_(subfilter)
, digest_context_(NULL) {}
~SignatureCallbackImpl();
virtual void Release() {
delete this;
}
virtual bool StartCalcDigest(const ReaderCallback* file, const uint32* byte_range_array,
uint32 size_of_array, const Signature& signature, const void* client_data);
virtual Progressive::State ContinueCalcDigest(const void* client_data, const PauseCallback* pause);
virtual String GetDigest(const void* client_data);
virtual String Sign(const void* digest, uint32 digest_length, const wchar_t* cert_path,
const WString& password, Signature::DigestAlgorithm digest_algorithm,
void* client_data);
virtual uint32 VerifySigState(const void* digest, uint32 digest_length,
const void* signed_data, uint32 signed_data_len,
void* client_data);
virtual bool IsNeedPadData() {return false;}
protected:
bool GetTextFromFile(unsigned char *plainString);
unsigned char* PKCS7Sign(const wchar_t* cert_file_path, String cert_file_password,
String plain_text, int& signed_data_size);
bool PKCS7VerifySignature(String signed_data, String plain_text);
bool ParseP12File(const wchar_t* cert_file_path, String cert_file_password,
EVP_PKEY** pkey, X509** x509, STACK_OF(X509)** ca);
ASN1_INTEGER* CreateNonce(int bits);
private:
string sub_filter_;
DigestContext* digest_context_;
string cert_file_path_;
string cert_file_password_;
};
SignatureCallbackImpl::~SignatureCallbackImpl() {
if (digest_context_) {
delete digest_context_;
digest_context_ = NULL;
}
}
bool SignatureCallbackImpl::GetTextFromFile(unsigned char* file_buffer) {
if (!digest_context_ || !digest_context_->GetFileReadCallback()) return false;
ReaderCallback* file_read = digest_context_->GetFileReadCallback();
file_read->ReadBlock(file_buffer, digest_context_->GetByteRangeElement(0), digest_context_->GetByteRangeElement(1));
file_read->ReadBlock(file_buffer + (digest_context_->GetByteRangeElement(1)-digest_context_->GetByteRangeElement(0)),
digest_context_->GetByteRangeElement(2), digest_context_->GetByteRangeElement(3));
return true;
}
bool SignatureCallbackImpl::StartCalcDigest(const ReaderCallback* file, const uint32* byte_range_array,
uint32 size_of_array, const Signature& signature, const void* client_data) {
if (digest_context_) {
delete digest_context_;
digest_context_ = NULL;
}
digest_context_ = new DigestContext(const_cast<ReaderCallback*>(file), byte_range_array, size_of_array);
if(!SHA1_Init(&digest_context_->sha_ctx_)) {
delete digest_context_;
digest_context_ = NULL;
return false;
}
return true;
}
Progressive::State SignatureCallbackImpl::ContinueCalcDigest(const void* client_data, const PauseCallback* pause) {
if (!digest_context_) return Progressive::e_Error;
uint32 file_length = digest_context_->GetByteRangeElement(1) + digest_context_->GetByteRangeElement(3);
unsigned char* file_buffer = (unsigned char*)malloc(file_length);
if (!file_buffer || !GetTextFromFile(file_buffer)) return Progressive::e_Error;
SHA1_Update(&digest_context_->sha_ctx_, file_buffer, file_length);
free(file_buffer);
return Progressive::e_Finished;
}
String SignatureCallbackImpl::GetDigest(const void* client_data) {
if (!digest_context_) return "";
unsigned char* md = reinterpret_cast<unsigned char*>(OPENSSL_malloc((SHA_DIGEST_LENGTH)*sizeof(unsigned char)));
if (1 != SHA1_Final(md, &digest_context_->sha_ctx_))
return "";
String digest = String(reinterpret_cast<const char*>(md), SHA_DIGEST_LENGTH);
OPENSSL_free(md);
return digest;
}
String SignatureCallbackImpl::Sign(const void* digest, uint32 digest_length, const wchar_t* cert_path,
const WString& password, Signature::DigestAlgorithm digest_algorithm,
void* client_data) {
if (!digest_context_) return "";
String plain_text;
if ("adbe.pkcs7.sha1" == sub_filter_) {
plain_text = String((const char*)digest, digest_length);
}
int signed_data_length = 0;
unsigned char* signed_data_buffer = PKCS7Sign(cert_path, String::FromUnicode(password),
plain_text, signed_data_length);
if (!signed_data_buffer) return "";
String signed_data = String((const char*)signed_data_buffer, signed_data_length);
free(signed_data_buffer);
return signed_data;
}
uint32 SignatureCallbackImpl::VerifySigState(const void* digest, uint32 digest_length,
const void* signed_data, uint32 signed_data_len, void* client_data) {
// Usually, the content of a signature field is contain the certification of signer.
// But we can't judge this certification is trusted.
// For this example, the signer is ourself. So when using api PKCS7_verify to verify,
// we pass NULL to it's parameter <i>certs</i>.
// Meanwhile, if application should specify the certificates, we suggest pass flag PKCS7_NOINTERN to
// api PKCS7_verify.
if (!digest_context_) return Signature::e_StateVerifyErrorData;
String plain_text;
unsigned char* file_buffer = NULL;
if ("adbe.pkcs7.sha1" == sub_filter_) {
plain_text = String(reinterpret_cast<const char*>(digest), digest_length);
} else {
return Signature::e_StateUnknown;
}
String signed_data_str = String(reinterpret_cast<const char*>(signed_data), signed_data_len);
bool ret = PKCS7VerifySignature(signed_data_str, plain_text);
if (file_buffer) free(file_buffer);
return ret ? Signature::e_StateVerifyNoChange : Signature::e_StateVerifyChange;
}
ASN1_INTEGER* SignatureCallbackImpl::CreateNonce(int bits) {
unsigned char buf[20];
int len = (bits - 1) / 8 + 1;
// Generating random byte sequence.
if (len > (int)sizeof(buf)) {
return NULL;
}
if (RAND_bytes(buf, len) <= 0) {
return NULL;
}
// Find the first non-zero byte and creating ASN1_INTEGER object.
int i = 0;
for (i = 0; i < len && !buf[i]; ++i) ;
ASN1_INTEGER* nonce = NULL;
if (!(nonce = ASN1_INTEGER_new())) {
ASN1_INTEGER_free(nonce);
return NULL;
}
OPENSSL_free(nonce->data);
// Allocate at least one byte.
nonce->length = len - i;
if (!(nonce->data = reinterpret_cast<unsigned char*>(OPENSSL_malloc(nonce->length + 1)))) {
ASN1_INTEGER_free(nonce);
return NULL;
}
memcpy(nonce->data, buf + i, nonce->length);
return nonce;
}
bool SignatureCallbackImpl::ParseP12File(const wchar_t* cert_file_path, String cert_file_password,
EVP_PKEY** pkey, X509** x509, STACK_OF(X509)** ca) {
FILE* file = NULL;
#if defined(_WIN32) || defined(_WIN64)
_wfopen_s(&file, cert_file_path, L"rb");
#else
file = fopen(String::FromUnicode(cert_file_path), "rb");
#endif // defined(_WIN32) || defined(_WIN64)
if (!file) {
return false;
}
PKCS12* pkcs12 = d2i_PKCS12_fp(file, NULL);
fclose (file);
if (!pkcs12) {
return false;
}
if (!PKCS12_parse(pkcs12, (const char*)cert_file_password, pkey, x509, ca)) {
return false;
}
PKCS12_free(pkcs12);
if (!pkey)
return false;
return true;
}
unsigned char* SignatureCallbackImpl::PKCS7Sign(const wchar_t* cert_file_path, String cert_file_password,
String plain_text, int& signed_data_size) {
PKCS7* p7 = NULL;
EVP_PKEY* pkey = NULL;
X509* x509 = NULL;
STACK_OF(X509)* ca = NULL;
if(!ParseP12File(cert_file_path, cert_file_password, &pkey, &x509, &ca))
return NULL;
p7 = PKCS7_new();
PKCS7_set_type(p7, NID_pkcs7_signed);
PKCS7_content_new(p7, NID_pkcs7_data);
// Application should not judge the sign algorithm with the content's length.
// Here, just for convenient;
if (plain_text.GetLength() > 32)
PKCS7_ctrl(p7, PKCS7_OP_SET_DETACHED_SIGNATURE, 1, NULL);
PKCS7_SIGNER_INFO* signer_info = PKCS7_add_signature(p7, x509, pkey, EVP_sha1());
PKCS7_add_certificate(p7, x509);
for (int i = 0; i< sk_num(CHECKED_STACK_OF(X509,ca)); i++)
PKCS7_add_certificate(p7, (X509*)sk_value(CHECKED_STACK_OF(X509,ca), i));
// Set source data to BIO.
BIO* p7bio = PKCS7_dataInit(p7, NULL);
BIO_write(p7bio, plain_text.GetBuffer(1), plain_text.GetLength());
PKCS7_dataFinal(p7, p7bio);
FREE_CERT_KEY;
BIO_free_all(p7bio);
// Get signed data.
unsigned long der_length = i2d_PKCS7(p7, NULL);
unsigned char* der = reinterpret_cast<unsigned char*>(malloc(der_length));
memset(der, 0, der_length);
unsigned char* der_temp = der;
i2d_PKCS7(p7, &der_temp);
PKCS7_free(p7);
signed_data_size = der_length;
return (unsigned char*)der;
}
bool SignatureCallbackImpl::PKCS7VerifySignature(String signed_data, String plain_text) {
// Retain PKCS7 object from signed data.
BIO* vin = BIO_new_mem_buf((void*)signed_data.GetBuffer(1), signed_data.GetLength());
PKCS7* p7 = d2i_PKCS7_bio(vin, NULL);
STACK_OF(PKCS7_SIGNER_INFO) *sk = PKCS7_get_signer_info(p7);
int sign_count = sk_PKCS7_SIGNER_INFO_num(sk);
int length = 0;
bool bSigAppr = false;
unsigned char *p = NULL;
for(int i=0;i<sign_count; i++) {
PKCS7_SIGNER_INFO* sign_info = sk_PKCS7_SIGNER_INFO_value(sk,i);
BIO *p7bio = BIO_new_mem_buf((void*)plain_text.GetBuffer(1), plain_text.GetLength());
X509 *x509= PKCS7_cert_from_signer_info(p7,sign_info);
if(1 == PKCS7_verify(p7, NULL, NULL,p7bio, NULL, PKCS7_NOVERIFY))
bSigAppr = true;
BIO_free(p7bio);
}
PKCS7_free(p7);
BIO_free(vin);
return bSigAppr;
}
C
#include "include/fs_basictypes_c.h"
#include "include/fs_annot_c.h"
#include "include/fs_image_c.h"
#include "include/fs_pdfdoc_c.h"
#include "include/fs_pdfpage_c.h"
#include "include/fs_signature_c.h"
// Implementation of pdf::SignatureCallback
// Used for implementing SignatureCallback.
typedef struct _DigestContext
{
SHA_CTX sha_ctx_;
FSReaderCallback* file_read_callback_;
FS_UINT32* byte_range_array_;
FS_UINT32 byte_range_array_size_;
FS_BSTR digest_;
FS_BSTR signed_data;
}DigestContext;
typedef struct _SignatureCallbackData
{
FS_BSTR sub_filter_;
DigestContext* digest_context_;
FS_BSTR cert_file_path_;
FS_BSTR cert_file_password_;
}SignatureCallbackData;
SignatureCallbackData gsignature_callback_data;
FS_BOOL GetTextFromFile(const DigestContext* digest_context_, unsigned char* file_buffer) {
FSReaderCallback* file_read;
FS_UINT32 offset;
FS_UINT32 size;
if (!digest_context_ || !digest_context_->file_read_callback_) return FALSE;
file_read = digest_context_->file_read_callback_;
offset = digest_context_->byte_range_array_[0];
size = digest_context_->byte_range_array_[1];
file_read->ReadBlock(file_read->user_data, file_buffer, digest_context_->byte_range_array_[0], digest_context_->byte_range_array_[1]);
file_read->ReadBlock(file_read->user_data, file_buffer + (digest_context_->byte_range_array_[1] - digest_context_->byte_range_array_[0]),
digest_context_->byte_range_array_[2], digest_context_->byte_range_array_[3]);
return TRUE;
}
FS_BOOL ParseP12File(const wchar_t* cert_file_path, char* cert_file_password,
EVP_PKEY** pkey, X509** x509, STACK_OF(X509)** ca) {
FILE* file = NULL;
PKCS12* pkcs12;
#if defined(_WIN32) || defined(_WIN64)
_wfopen_s(&file, cert_file_path, L"rb");
#else
file = fopen(string::FromUnicode(cert_file_path), "rb");
#endif // defined(_WIN32) || defined(_WIN64)
if (!file) {
return FALSE;
}
pkcs12 = d2i_PKCS12_fp(file, NULL);
fclose(file);
if (!pkcs12) {
return FALSE;
}
if (!PKCS12_parse(pkcs12, cert_file_password, pkey, x509, ca)) {
return TRUE;
}
PKCS12_free(pkcs12);
if (!pkey)
return FALSE;
return TRUE;
}
#define HANDLE_CREATE_TS_ERROR {\
if (!ret) {\
S_REQ_free(ts_req);\
ts_req = NULL;\
printf("could not create query\n");\
}
TS_MSG_IMPRINT_free(msg_imprint);\
X509_ALGOR_free(algo);\
ASN1_OBJECT_free(policy_obj);\
ASN1_INTEGER_free(nonce_asn1);\
return ts_req;\
ASN1_INTEGER *create_nonce(int bits)
{
unsigned char buf[20];
ASN1_INTEGER *nonce = NULL;
int len = (bits - 1) / 8 + 1;
int i;
/* Generating random byte sequence. */
if (len > (int)sizeof(buf))
{
printf("bit count error\n");
ASN1_INTEGER_free(nonce);
return NULL;
}
if (RAND_bytes(buf, len) <= 0)
{
printf("can not generate random number\n");
ASN1_INTEGER_free(nonce);
return NULL;
}
/* Find the first non-zero byte and creating ASN1_INTEGER object. */
for (i = 0; i < len && !buf[i]; ++i);
if (!(nonce = ASN1_INTEGER_new()))
{
printf("could not create nonce\n");
ASN1_INTEGER_free(nonce);
return NULL;
}
OPENSSL_free(nonce->data);
/* Allocate at least one byte. */
nonce->length = len - i;
if (!(nonce->data = (unsigned char *)OPENSSL_malloc(nonce->length + 1)))
{
printf("out of memory\n");
ASN1_INTEGER_free(nonce);
return NULL;
}
memcpy(nonce->data, buf + i, nonce->length);
return nonce;
}
TS_REQ *create_ts_query(unsigned char *digest, int len)
{
int ret = 0;
TS_REQ *ts_req = NULL;
const EVP_MD *md;
TS_MSG_IMPRINT *msg_imprint = NULL;
X509_ALGOR *algo = NULL;
ASN1_OBJECT *policy_obj = NULL;
ASN1_INTEGER *nonce_asn1 = NULL;
switch (len) {
case 20:
md = EVP_get_digestbyname("sha1");
break;
case 32:
md = EVP_get_digestbyname("sha256");
break;
default:
HANDLE_CREATE_TS_ERROR;
}
/* Creating request object. */
if (!(ts_req = TS_REQ_new()))
HANDLE_CREATE_TS_ERROR;
/* Setting version. */
if (!TS_REQ_set_version(ts_req, 1))
HANDLE_CREATE_TS_ERROR;
/* Creating and adding MSG_IMPRINT object. */
if (!(msg_imprint = TS_MSG_IMPRINT_new()))
HANDLE_CREATE_TS_ERROR;
/* Adding algorithm. */
if (!(algo = X509_ALGOR_new()))
HANDLE_CREATE_TS_ERROR;
if (!(algo->algorithm = OBJ_nid2obj(EVP_MD_type(md))))
HANDLE_CREATE_TS_ERROR;
if (!(algo->parameter = ASN1_TYPE_new()))
HANDLE_CREATE_TS_ERROR;
algo->parameter->type = V_ASN1_NULL;
if (!TS_MSG_IMPRINT_set_algo(msg_imprint, algo))
HANDLE_CREATE_TS_ERROR;
if (!TS_MSG_IMPRINT_set_msg(msg_imprint, digest, len))
HANDLE_CREATE_TS_ERROR;
if (!TS_REQ_set_msg_imprint(ts_req, msg_imprint))
HANDLE_CREATE_TS_ERROR;
/* Setting nonce if requested. */
if (!(nonce_asn1 = create_nonce(64)))
HANDLE_CREATE_TS_ERROR;
if (nonce_asn1 && !TS_REQ_set_nonce(ts_req, nonce_asn1))
HANDLE_CREATE_TS_ERROR;
/* Setting certificate request flag if requested. */
if (!TS_REQ_set_cert_req(ts_req, 1))
HANDLE_CREATE_TS_ERROR;
ret = 1;
HANDLE_CREATE_TS_ERROR;
}
long Get_TS_REP(unsigned char *md, int md_len, unsigned char **pRet)
{
unsigned char *p;
unsigned char *tsReq;
int len;
char SendBuffer[1024] = { 0 };
const char* bsAuth = ":";
FS_BSTR bsDestAuth;
WSADATA Ws;
SOCKET CientSocket;
unsigned char *totalBuf;
struct sockaddr_in ServerAddr;
int Ret = 0;
int AddrLen = 0;
HOSTENT * iphost;
char serverIP[20] = "";
struct servent *pST;
int sendLen;
char recvBuf[8096] = { 0 };
int revtotalLen = 0, recTSL = 0;
int revLen;
int nTSRepPos = 0;
int tsrepL = 0;
char rspCode[4] = { 0 };
char *ptr = NULL;
TS_REQ *request = create_ts_query(md, md_len);
len = i2d_TS_REQ(request, NULL);
tsReq = (unsigned char *)OPENSSL_malloc(len);
p = tsReq;
len = i2d_TS_REQ(request, (unsigned char **)&p);
TS_REQ_free(request);
FSDK_Codec_Base64Encode(bsAuth, 1*sizeof(char), &bsDestAuth);
sprintf_s(SendBuffer, 1024, "GET %s HTTP/1.1\r\n"
"Accept: */*\r\n"
"Content-Type: application/timestamp-query\r\n"
"Content-Length: %d\r\n"
"Character-Encoding: binary\r\n"
"User-Agent: PPKHandler\r\n"
"Host: %s\r\n"
"Connection: Keep-Alive\r\n"
"Cache-Control: no-cache\r\n"
"Authorization: Basic %s\r\n"
"\r\n",
"/TSAServer.aspx", len, "ca.signfiles.com", bsDestAuth.str);
totalBuf = (unsigned char *)malloc(len + strlen(SendBuffer));
memcpy(totalBuf, SendBuffer, strlen(SendBuffer));
memcpy(totalBuf + strlen(SendBuffer), tsReq, len);
OPENSSL_free(tsReq);
WSAStartup(MAKEWORD(2, 2), &Ws);
CientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ((iphost = gethostbyname("ca.signfiles.com")) != NULL)
{
int i = 0;
while (iphost->h_addr_list[i])
{
memcpy(&serverIP, inet_ntoa(*((struct in_addr *)iphost->h_addr_list[i])), 20);
i++;
}
}
pST = getservbyname("http", NULL);
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_addr.s_addr = inet_addr(serverIP);
ServerAddr.sin_port = pST->s_port;
memset(ServerAddr.sin_zero, 0x00, 8);
connect(CientSocket, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr));
sendLen = send(CientSocket, (const char *)totalBuf, len + (int)strlen(SendBuffer), 0);
free(totalBuf);
revLen = recv(CientSocket, recvBuf, 8096, 0);
if (revLen == 0)
{
printf("\r\ntsa server unreachable.\r\n");
closesocket(CientSocket);
WSACleanup();
return 0;
}
revtotalLen += revLen;
//get the ts reponse length
strncpy_s(rspCode, 4, recvBuf + 9, 3);
if (strcmp(rspCode, "200") != 0)
{
printf("\r\n tsa server refuse request.\r\n%s\r\n", recvBuf);
closesocket(CientSocket);
WSACleanup();
return 0;
}
ptr = strstr(recvBuf, "Content-Length") + strlen("Content-Length") + 2;
//nTSRepPos = (int)(strRecv.find("Content-Length") + strlen("Content-Length") + 2);
while (*ptr > 47 && *ptr < 58)
{
tsrepL = tsrepL * 10 + *ptr - 48;
ptr += 1;
}
while (recTSL < tsrepL && revtotalLen < tsrepL)
{
printf("retry, len:%d\n", revLen);
revLen = recv(CientSocket, recvBuf + revtotalLen, 8096 - revtotalLen, 0);
recTSL += revLen;
revtotalLen += revLen;
}
*pRet = (unsigned char *)OPENSSL_malloc(tsrepL);
memcpy(*pRet, recvBuf + revtotalLen - tsrepL, tsrepL);
closesocket(CientSocket);
WSACleanup();
return tsrepL;
}
int append_tsp_token(PKCS7_SIGNER_INFO *sinfo, unsigned char *ts_rep, long tsrepL)
{
unsigned char *p = ts_rep;
TS_RESP *tsp = d2i_TS_RESP(NULL, (const unsigned char**)&p, tsrepL);
if (tsp != NULL)
{
int p7_len;
unsigned char *p7_der = NULL;
unsigned char *p = NULL;
PKCS7* token = TS_RESP_get_token(tsp);
if (!PKCS7_type_is_signed(token))
{
printf("Error in timestamp token: not signed!\n");
return 1;
}
p7_len = i2d_PKCS7(token, NULL);
p7_der = (unsigned char *)OPENSSL_malloc(p7_len);
p = p7_der;
i2d_PKCS7(token, &p);
if (sinfo)
{
//Add timestamp token to the PKCS7 signature object
ASN1_STRING *value = ASN1_STRING_new();
ASN1_STRING_set(value, p7_der, p7_len);
PKCS7_add_attribute(sinfo, NID_id_smime_aa_timeStampToken, V_ASN1_SEQUENCE, value);
OPENSSL_free(p7_der);
}
} else {
printf("Error decoding timestamp token!\n");
return 1;
}
return 0;
}
FS_BOOL gStartCalcDigest(void* user_data, const FSReaderCallback* file, const FS_UINT32* byte_range_array,
FS_UINT32 size_of_array, const FS_SIGNATURE_HANDLE signature, const void* client_data) {
if (gsignature_callback_data.digest_context_) {
free(gsignature_callback_data.digest_context_);
gsignature_callback_data.digest_context_ = NULL;
}
gsignature_callback_data.digest_context_ = (DigestContext*)malloc(sizeof(DigestContext));
FSDK_BStr_Init(&gsignature_callback_data.digest_context_->signed_data);
FSDK_BStr_Init(&gsignature_callback_data.digest_context_->digest_);
gsignature_callback_data.digest_context_->file_read_callback_ = (FSReaderCallback*)file;
gsignature_callback_data.digest_context_->byte_range_array_ = (FS_UINT32*)byte_range_array;
gsignature_callback_data.digest_context_->byte_range_array_size_ = size_of_array;
if (!SHA1_Init(&(gsignature_callback_data.digest_context_->sha_ctx_))) {
free(gsignature_callback_data.digest_context_);
gsignature_callback_data.digest_context_ = NULL;
return FALSE;
}
return TRUE;
}
FSState gContinueCalcDigest(void* user_data, const void* client_data, const FSPauseCallback* pause) {
FS_UINT32 file_length;
unsigned char* file_buffer;
if (!gsignature_callback_data.digest_context_) return e_FSError;
file_length = gsignature_callback_data.digest_context_->byte_range_array_[1] + gsignature_callback_data.digest_context_->byte_range_array_[3];
file_buffer = (unsigned char*)malloc(file_length);
if (!file_buffer || !GetTextFromFile(gsignature_callback_data.digest_context_, file_buffer)) return e_FSError;
SHA1_Update(&(gsignature_callback_data.digest_context_->sha_ctx_), file_buffer, file_length);
free(file_buffer);
return e_FSFinished;
}
FS_BSTR gGetDigest(void* user_data, const void* client_data) {
FS_BSTR digest;
unsigned char* md;
if (!gsignature_callback_data.digest_context_) {
digest.str = NULL;
digest.len = 0;
return digest;
};
md = (unsigned char*)(OPENSSL_malloc((SHA_DIGEST_LENGTH) * sizeof(unsigned char)));
if (1 != SHA1_Final(md, &(gsignature_callback_data.digest_context_->sha_ctx_))) {
digest.str = NULL;
digest.len = 0;
return digest;
}
if (gsignature_callback_data.digest_context_->digest_.str) {
FSDK_BStr_Clear(&gsignature_callback_data.digest_context_->digest_);
}
FSDK_BStr_SetLength(&gsignature_callback_data.digest_context_->digest_, SHA_DIGEST_LENGTH);
FSDK_BStr_Set(&gsignature_callback_data.digest_context_->digest_, (const char*)md, SHA_DIGEST_LENGTH);
OPENSSL_free(md);
return gsignature_callback_data.digest_context_->digest_;
}
unsigned char* PKCS7Sign(const wchar_t* cert_file_path, char* cert_file_password,
char* plain_text, int plain_text_size, int* signed_data_size);
FS_BOOL PKCS7VerifySignature(FS_BSTR signed_data, FS_BSTR plain_text);
FS_BSTR gSign(void* user_data, const void* digest, FS_UINT32 digest_length, const wchar_t* cert_path,
const wchar_t* password, FSDigestAlgorithm digest_algorithm,
void* client_data) {
FS_BSTR bstr;
char* plain_text = NULL;
int signed_data_length = 0;
size_t password_size;
size_t pass_word_size;
char* pass_word = NULL;
unsigned char* signed_data_buffer;
bstr.str = NULL;
bstr.len = 0;
if (!gsignature_callback_data.digest_context_) {
return bstr;
}
if(strcmp("adbe.pkcs7.sha1", gsignature_callback_data.sub_filter_.str) == 0) {
plain_text = (char*)malloc(digest_length);
memcpy(plain_text, digest, digest_length);
}
password_size = wcslen(password);
pass_word_size = password_size + 1;
pass_word = (char*)malloc(pass_word_size);
signed_data_buffer = PKCS7Sign(cert_path, wstring2string(password, password_size, pass_word, pass_word_size),
plain_text, digest_length, &signed_data_length);
free(pass_word);
free(plain_text);
if (!signed_data_buffer) return bstr;
if (!gsignature_callback_data.digest_context_->signed_data.str) {
FSDK_BStr_Clear(&gsignature_callback_data.digest_context_->signed_data);
}
FSDK_BStr_SetLength(&gsignature_callback_data.digest_context_->signed_data, signed_data_length);
FSDK_BStr_Set(&gsignature_callback_data.digest_context_->signed_data, (char*)(const char*)signed_data_buffer, signed_data_length);
free(signed_data_buffer);
return gsignature_callback_data.digest_context_->signed_data;
}
FS_BSTR gSign0(void* user_data, const void* digest, FS_UINT32 digest_length, FSIFX_FileStream* cert_file_stream, const wchar_t* password, FSDigestAlgorithm digest_algorithm, void* client_data) {
FS_BSTR bstr;
bstr.str = "";
bstr.len = 0;
return bstr;
}
FS_UINT32 gVerifySigState(void* user_data, const void* digest, FS_UINT32 digest_length,const void* signed_data, FS_UINT32 signed_data_len,void* client_data) {
// Usually, the content of a signature field is contain the certification of signer.
// But we can't judge this certification is trusted.
// For this example, the signer is ourself. So when using api PKCS7_verify to verify,
// we pass NULL to it's parameter <i>certs</i>.
// Meanwhile, if application should specify the certificates, we suggest pass flag PKCS7_NOINTERN to
// api PKCS7_verify.
FS_BSTR plain_text;
unsigned char* file_buffer = NULL;
FS_BSTR signed_data_str;
FS_BOOL ret;
if (!gsignature_callback_data.digest_context_) return e_FSStateVerifyErrorData;
if (strcmp("adbe.pkcs7.sha1", gsignature_callback_data.sub_filter_.str) == 0) {
FSDK_BStr_Init(&plain_text);
FSDK_BStr_SetLength(&plain_text, digest_length);
FSDK_BStr_Set(&plain_text, digest, digest_length);
} else {
return e_FSStatesStateUnknown;
}
FSDK_BStr_Init(&signed_data_str);
FSDK_BStr_SetLength(&signed_data_str, signed_data_len);
FSDK_BStr_Set(&signed_data_str, signed_data, signed_data_len);
ret = PKCS7VerifySignature(signed_data_str, plain_text);
if (file_buffer) free(file_buffer);
FSDK_BStr_Clear(&signed_data_str);
FSDK_BStr_Clear(&plain_text);
//this function is only used to verify the intergrity of a signature.
return ret ? e_FSStateVerifyNoChange : e_FSStateVerifyChange;
}
void gRelease(void* user_data) {
FSDK_BStr_Clear(&gsignature_callback_data.sub_filter_);
FSDK_BStr_Clear(&gsignature_callback_data.cert_file_path_);
FSDK_BStr_Clear(&gsignature_callback_data.cert_file_password_);
FSDK_BStr_Clear(&gsignature_callback_data.digest_context_->digest_);
FSDK_BStr_Clear(&gsignature_callback_data.digest_context_->signed_data);
free(gsignature_callback_data.digest_context_);
free(user_data);
}
FS_BOOL gIsNeedPadData(void* user_data) { return FALSE; }
FSCertValidity gCheckCertificateValidity(void* user_data, const wchar_t* cert_path, const wchar_t* cert_password, void* client_data) {
// User can check the validity of input certificate here.
// If no need to check, just return e_CertValid.
return e_FSCertValid;
}
java
import com.foxit.sdk.pdf.*;
...
// Implementation of SignatureCallback
class SignatureCallbackImpl extends SignatureCallback {
private String sub_filter_;
private DigestContext digest_context_ = null;
byte[] arrall = null;
SignatureCallbackImpl(String subfilter) {
sub_filter_ = subfilter;
}
@Override
public boolean startCalcDigest(FileReaderCallback var1, int[] var2,
com.foxit.sdk.pdf.Signature var3, Object var4) {
digest_context_ = new DigestContext(var1, var2, var2.length);
return true;
}
@Override
public int continueCalcDigest(Object var1, PauseCallback var2) {
return com.foxit.sdk.common.Progressive.e_Finished;
}
@Override
public byte[] getDigest(Object var1) {
return arrall;
}
@Override
public byte[] sign(byte[] digest, String cert_path, byte[] cert_password, int digest_algorithm, java.lang.Object client_data){
String encryptStr = null;
try {
try {
FileReaderCallback filehandler = digest_context_.file_read_callback_;
{
long size = filehandler.getSize();
byte[] arr1 = new byte[digest_context_.byte_range_array_[1]];
filehandler.readBlock(arr1,
digest_context_.byte_range_array_[0],
digest_context_.byte_range_array_[1]);
byte[] arr2 = new byte[digest_context_.byte_range_array_[3]];
filehandler.readBlock(arr2,
digest_context_.byte_range_array_[2],
digest_context_.byte_range_array_[3]);
size = 0;
arrall = new byte[(int) digest_context_.byte_range_array_[1]
+ (int) digest_context_.byte_range_array_[3]];
System.arraycopy(arr1, 0, arrall, 0, arr1.length);
System.arraycopy(arr2, 0, arrall, arr1.length, arr2.length);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
encryptStr = CertUtil.SignMsg(arrall, signature.input_path
+ "foxit_all.pfx", "123456");
return encryptStr.getBytes();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@Override
public byte[] sign(byte[] digest, StreamCallback cert_path, byte[] cert_password, int digest_algorithm, java.lang.Object client_data){
return null;
}
@Override
public int verifySigState(byte[] var1, byte[] var2, Object var3) {
byte[] arrall_verify = null;
boolean verify_state = false;
try {
verify_state = CertUtil.VerifyMsg(new String(var2).toLowerCase(), arrall,
signature.input_path + "foxit.cer");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return verify_state ? com.foxit.sdk.pdf.Signature.e_StateVerifyNoChange : com.foxit.sdk.pdf.Signature.e_StateVerifyChange;
}
@Override
public boolean isNeedPadData() {return false;}
}
...
py
import sys
import site
if sys.version_info.major == 2:
_PYTHON2_ = True
else:
_PYTHON2_ = False
if _PYTHON2_:
#replace with the python2 lib path
site.addsitedir('../../../')
from FoxitPDFSDKPython2 import *
else:
from FoxitPDFSDKPython3 import *
…
# Implementation of pdf.SignatureCallback
class SignatureCallbackImpl(SignatureCallback):
def __init__(self, *args):
if _PYTHON2_:
super(SignatureCallbackImpl, self).__init__()
else:
super().__init__()
self.digest_context_ = None
self.sub_filter_ = args[0]
def __del__(self):
self.__disown__()
def Release(self):
pass
def GetTextFromFile(self, *args):
file_buffer = None
if self.digest_context_ is None or not self.digest_context_.GetFileReadCallback(
):
return False, None
file_read = self.digest_context_.GetFileReadCallback()
val, buffer = file_read.ReadBlock(
(self.digest_context_.GetByteRangeElement(0),
self.digest_context_.GetByteRangeElement(1)))
file_buffer = buffer
val, buffer = file_read.ReadBlock(
(self.digest_context_.GetByteRangeElement(2),
self.digest_context_.GetByteRangeElement(3)))
file_buffer += buffer
return True, file_buffer
def StartCalcDigest(self, *args):
file = args[0]
byte_range_array = args[1]
size_of_array = len(args[1])
signature = args[2]
client_data = args[3]
self.digest_context_ = DigestContext(file, byte_range_array,
size_of_array)
return self.digest_context_.HashInit()
def ContinueCalcDigest(self, *args):
try:
if self.digest_context_ is None:
return Progressive.e_Error
ret, file_buffer = self.GetTextFromFile()
if not ret:
return Progressive.e_Error
self.digest_context_.HashUpdate(file_buffer)
return Progressive.e_Finished
except Exception as ex:
print(ex.GetMessage())
return Progressive.e_Error
def GetDigest(self, *args):
try:
if self.digest_context_ is None:
return ""
digest = self.digest_context_.HashDigest()
return digest
except Exception as ex:
print(ex.GetMessage())
return ""
def Sign(self, *args):
try:
digest = args[0][0]
digest_length = args[0][1]
cert_path = args[1]
password = args[2]
digest_algorithm = args[3]
client_data = args[4]
if self.digest_context_ is None:
return ""
plain_text = ""
if "adbe.pkcs7.sha1" == self.sub_filter_:
plain_text = digest
pk12 = crypto.load_pkcs12(open(cert_path, 'rb').read(), password)
pkey = pk12.get_privatekey()
signcert = pk12.get_certificate()
PKCS7_NOSIGS = 0x4
bio_in = crypto._new_mem_buf(plain_text)
pkcs7 = crypto._lib.PKCS7_sign(signcert._x509, pkey._pkey,
crypto._ffi.NULL, bio_in,
PKCS7_NOSIGS)
bio_out = crypto._new_mem_buf()
crypto._lib.i2d_PKCS7_bio(bio_out, pkcs7)
signed_data = crypto._bio_to_string(bio_out)
return signed_data
except Exception as ex:
print(ex.GetMessage())
return ""
def VerifySigState(self, *args):
# Usually, the content of a signature field is contain the certification of signer.
# But we can't judge this certification is trusted.
# For this example, the signer is ourself. So when using api PKCS7_verify to verify,
# we pass NULL to it's parameter <i>certs</i>.
# Meanwhile, if application should specify the certificates, we suggest pass flag PKCS7_NOINTERN to
# api PKCS7_verify.
if self.digest_context_ is None:
return Signature.e_StateVerifyErrorData
plain_text = ""
digest = args[0][0]
digest_length = args[0][1]
signed_data = args[1][0]
signed_data_len = args[1][1]
client_data = args[2]
if "adbe.pkcs7.sha1" != self.sub_filter_:
return Signature.e_StateUnknown
p7 = crypto.load_pkcs7_data(crypto.FILETYPE_ASN1, signed_data)
PKCS7_NOVERIFY = 0x20
p7bio = crypto._new_mem_buf(digest)
res = crypto._lib.PKCS7_verify(p7._pkcs7, crypto._ffi.NULL,
crypto._ffi.NULL, p7bio,
crypto._ffi.NULL, PKCS7_NOVERIFY)
if res:
return Signature.e_StateVerifyNoChange
else:
return Signature.e_StateVerifyChange
def IsNeedPadData(self, *args):
return False
def CheckCertificateValidity(self, *args):
# User can check the validity of input certificate here.
# If no need to check, just return e_CertValid.
return SignatureCallback.e_CertValid
objc
#include "FSPDFObjC.h"
#include "openssl/rsa.h"
#include "openssl/evp.h"
#include "openssl/objects.h"
#include "openssl/x509.h"
#include "openssl/err.h"
#include "openssl/pem.h"
#include "openssl/ssl.h"
#include "openssl/pkcs12.h"
#include "openssl/rand.h"
#include "openssl/pkcs7.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <string>
// some base type declarations
typedef std::string String;
// Used for implementing SignatureCallback.
class DigestContext {
public:
DigestContext(id<FSFileReaderCallback> file_read_callback, NSArray<NSNumber *> *byte_range_array)
: file_read_callback_(file_read_callback), byte_range_array_(byte_range_array) {}
~DigestContext() {}
id<FSFileReaderCallback> GetFileReadCallback() {
return file_read_callback_;
}
NSUInteger GetByteRangeSize() {
return byte_range_array_.count;
}
unsigned int GetByteRangeElement(NSUInteger index) {
if (!byte_range_array_)
return 0;
return [byte_range_array_[index] unsignedIntValue];
}
SHA_CTX sha_ctx_;
protected:
id<FSFileReaderCallback> file_read_callback_;
NSArray<NSNumber *> *byte_range_array_;
};
// Implementation of pdf::SignatureCallback
class SignatureCallbackImpl {
public:
SignatureCallbackImpl(std::string subfilter)
: sub_filter_(subfilter), digest_context_(NULL) {}
~SignatureCallbackImpl();
void Release() {
delete this;
}
bool StartCalcDigest(id<FSFileReaderCallback> file, NSArray<NSNumber *> *byte_range_array, FSSignature *signature, const void *client_data);
FSProgressiveState ContinueCalcDigest(const void *client_data, id<FSPauseCallback> pause);
NSData *GetDigest(const void *client_data);
NSData *Sign(const void *digest, uint32 digest_length, std::string cert_path,
std::string password, FSSignatureDigestAlgorithm digest_algorithm,
void *client_data);
NSData *Sign(const void *digest, uint32 digest_length, id<FSFileStreamCallback> cert_file_stream,
std::string password, FSSignatureDigestAlgorithm digest_algorithm, void *client_data);
FSSignatureStates VerifySigState(const void *digest, uint32 digest_length,
const void *signed_data, uint32 signed_data_len,
void *client_data);
bool IsNeedPadData() { return false; }
protected:
bool GetTextFromFile(unsigned char *plainString);
unsigned char *PKCS7Sign(std::string cert_file_path, String cert_file_password,
String plain_text, int &signed_data_size);
bool PKCS7VerifySignature(String signed_data, String plain_text);
bool ParseP12File(std::string cert_file_path, String cert_file_password,
EVP_PKEY **pkey, X509 **x509, STACK_OF(X509) * *ca);
ASN1_INTEGER *CreateNonce(int bits);
private:
std::string sub_filter_;
DigestContext *digest_context_;
std::string cert_file_path_;
std::string cert_file_password_;
};
#define FREE_CERT_KEY if(pkey)\
EVP_PKEY_free(pkey);\
if(x509)\
X509_free(x509);\
if(ca)\
sk_X509_free(ca);
void InitializeOpenssl() {
// SSLeay_add_all_algorithms();
}
SignatureCallbackImpl::~SignatureCallbackImpl() {
if (digest_context_) {
delete digest_context_;
digest_context_ = NULL;
}
}
bool SignatureCallbackImpl::GetTextFromFile(unsigned char *file_buffer) {
if (!digest_context_ || !digest_context_->GetFileReadCallback())
return false;
id<FSFileReaderCallback> file_read = digest_context_->GetFileReadCallback();
NSData *data = [file_read readBlock:digest_context_->GetByteRangeElement(0) size:digest_context_->GetByteRangeElement(1)];
[data getBytes:file_buffer length:data.length];
data = [file_read readBlock:digest_context_->GetByteRangeElement(2) size:digest_context_->GetByteRangeElement(3)];
[data getBytes:file_buffer + (digest_context_->GetByteRangeElement(1) - digest_context_->GetByteRangeElement(0)) length:data.length];
return true;
}
bool SignatureCallbackImpl::StartCalcDigest(id<FSFileReaderCallback> file, NSArray<NSNumber *> *byte_range_array, FSSignature *signature, const void *client_data) {
if (digest_context_) {
delete digest_context_;
digest_context_ = NULL;
}
digest_context_ = new DigestContext(file, byte_range_array);
if (!SHA1_Init(&digest_context_->sha_ctx_)) {
delete digest_context_;
digest_context_ = NULL;
return false;
}
return true;
}
FSProgressiveState SignatureCallbackImpl::ContinueCalcDigest(const void *client_data, id<FSPauseCallback> pause) {
if (!digest_context_)
return FSProgressiveError;
uint32 file_length = digest_context_->GetByteRangeElement(1) + digest_context_->GetByteRangeElement(3);
unsigned char *file_buffer = (unsigned char *) malloc(file_length);
if (!file_buffer || !GetTextFromFile(file_buffer))
return FSProgressiveError;
SHA1_Update(&digest_context_->sha_ctx_, file_buffer, file_length);
free(file_buffer);
return FSProgressiveFinished;
}
NSData *SignatureCallbackImpl::GetDigest(const void *client_data) {
if (!digest_context_)
return nil;
unsigned char *md = reinterpret_cast<unsigned char *>(OPENSSL_malloc((SHA_DIGEST_LENGTH) * sizeof(unsigned char)));
if (1 != SHA1_Final(md, &digest_context_->sha_ctx_))
return nil;
NSData *digest = [NSData dataWithBytes:reinterpret_cast<const void *>(md) length:SHA_DIGEST_LENGTH];
OPENSSL_free(md);
return digest;
}
NSData *SignatureCallbackImpl::Sign(const void *digest, uint32 digest_length, std::string cert_path,
std::string password, FSSignatureDigestAlgorithm digest_algorithm,
void *client_data) {
if (!digest_context_)
return nil;
String plain_text;
if ("adbe.pkcs7.sha1" == sub_filter_) {
plain_text = String((const char *) digest, digest_length);
}
int signed_data_length = 0;
unsigned char *signed_data_buffer = PKCS7Sign(cert_path, password,
plain_text, signed_data_length);
if (!signed_data_buffer)
return nil;
NSData *signed_data = [NSData dataWithBytes:(const void *) signed_data_buffer length:signed_data_length];
free(signed_data_buffer);
return signed_data;
}
NSData *Sign(const void *digest, uint32 digest_length, id<FSFileStreamCallback> cert_file_stream,
std::string password, FSSignatureDigestAlgorithm digest_algorithm, void *client_data) {
return nil;
}
FSSignatureStates SignatureCallbackImpl::VerifySigState(const void *digest, uint32 digest_length,
const void *signed_data, uint32 signed_data_len, void *client_data) {
// Usually, the content of a signature field is containing the certification of signer.
// But we can't judge this certification is trusted.
// For this example, the signer is ourself. So when using api PKCS7_verify to verify,
// we pass NULL to it's parameter <i>certs</i>.
// Meanwhile, if application should specify the certificates, we suggest pass flag PKCS7_NOINTERN to
// api PKCS7_verify.
if (!digest_context_)
return FSSignatureStateVerifyErrorData;
String plain_text;
unsigned char *file_buffer = NULL;
if ("adbe.pkcs7.sha1" == sub_filter_) {
plain_text = String(reinterpret_cast<const char *>(digest), digest_length);
} else {
return FSSignatureStateUnknown;
}
String signed_data_str = String(reinterpret_cast<const char *>(signed_data), signed_data_len);
bool ret = PKCS7VerifySignature(signed_data_str, plain_text);
if (file_buffer)
free(file_buffer);
return ret ? FSSignatureStateVerifyNoChange: FSSignatureStateVerifyChange;
}
ASN1_INTEGER *SignatureCallbackImpl::CreateNonce(int bits) {
unsigned char buf[20];
int len = (bits - 1) / 8 + 1;
// Generating random byte sequence.
if (len > (int) sizeof(buf)) {
return NULL;
}
if (RAND_bytes(buf, len) <= 0) {
return NULL;
}
// Find the first non-zero byte and creating ASN1_INTEGER object.
int i = 0;
for (i = 0; i < len && !buf[i]; ++i)
;
ASN1_INTEGER *nonce = NULL;
if (!(nonce = ASN1_INTEGER_new())) {
ASN1_INTEGER_free(nonce);
return NULL;
}
OPENSSL_free(nonce->data);
// Allocate at least one byte.
nonce->length = len - i;
if (!(nonce->data = reinterpret_cast<unsigned char *>(OPENSSL_malloc(nonce->length + 1)))) {
ASN1_INTEGER_free(nonce);
return NULL;
}
memcpy(nonce->data, buf + i, nonce->length);
return nonce;
}
bool SignatureCallbackImpl::ParseP12File(std::string cert_file_path, String cert_file_password,
EVP_PKEY **pkey, X509 **x509, STACK_OF(X509) * *ca) {
FILE *file = NULL;
#if defined(_WIN32) || defined(_WIN64)
_wfopen_s(&file, cert_file_path, @"rb");
#else
file = fopen(cert_file_path.c_str(), "rb");
#endif // defined(_WIN32) || defined(_WIN64)
if (!file) {
return false;
}
PKCS12 *pkcs12 = d2i_PKCS12_fp(file, NULL);
fclose(file);
if (!pkcs12) {
return false;
}
if (!PKCS12_parse(pkcs12, cert_file_password.c_str(), pkey, x509, ca)) {
return false;
}
PKCS12_free(pkcs12);
if (!pkey)
return false;
return true;
}
unsigned char *SignatureCallbackImpl::PKCS7Sign(std::string cert_file_path, String cert_file_password,
String plain_text, int &signed_data_size) {
PKCS7 *p7 = NULL;
EVP_PKEY *pkey = NULL;
X509 *x509 = NULL;
STACK_OF(X509) *ca = NULL;
if (!ParseP12File(cert_file_path, cert_file_password, &pkey, &x509, &ca))
return NULL;
p7 = PKCS7_new();
PKCS7_set_type(p7, NID_pkcs7_signed);
PKCS7_content_new(p7, NID_pkcs7_data);
// Application should not judge the sign algorithm with the content's length.
// Here, just for convenient;
if (plain_text.size() > 32)
PKCS7_ctrl(p7, PKCS7_OP_SET_DETACHED_SIGNATURE, 1, NULL);
PKCS7_SIGNER_INFO *signer_info = PKCS7_add_signature(p7, x509, pkey, EVP_sha1());
signer_info = NULL;
PKCS7_add_certificate(p7, x509);
# define CHECKED_STACK_OF(type, p) \
((_STACK*) (1 ? p : (STACK_OF(type)*)0))
for (int i = 0; i < sk_num(CHECKED_STACK_OF(X509, ca)); i++)
PKCS7_add_certificate(p7, (X509 *) sk_value(CHECKED_STACK_OF(X509, ca), i));
// Set source data to BIO.
BIO *p7bio = PKCS7_dataInit(p7, NULL);
BIO_write(p7bio, plain_text.c_str(), (int) plain_text.size());
PKCS7_dataFinal(p7, p7bio);
FREE_CERT_KEY;
BIO_free_all(p7bio);
// Get signed data.
unsigned long der_length = i2d_PKCS7(p7, NULL);
unsigned char *der = reinterpret_cast<unsigned char *>(malloc(der_length));
memset(der, 0, der_length);
unsigned char *der_temp = der;
i2d_PKCS7(p7, &der_temp);
PKCS7_free(p7);
signed_data_size = (int) der_length;
return (unsigned char *) der;
}
bool SignatureCallbackImpl::PKCS7VerifySignature(String signed_data, String plain_text) {
// Retain PKCS7 object from signed data.
BIO *vin = BIO_new_mem_buf((void *) signed_data.c_str(), (int) signed_data.size());
PKCS7 *p7 = d2i_PKCS7_bio(vin, NULL);
STACK_OF(PKCS7_SIGNER_INFO) *sk = PKCS7_get_signer_info(p7);
int sign_count = sk_PKCS7_SIGNER_INFO_num(sk);
// int length = 0;
bool bSigAppr = false;
// unsigned char *p = NULL;
for (int i = 0; i < sign_count; i++) {
PKCS7_SIGNER_INFO *sign_info = sk_PKCS7_SIGNER_INFO_value(sk, i);
BIO *p7bio = BIO_new_mem_buf((void *) plain_text.c_str(), (int) plain_text.size());
X509 *x509 = PKCS7_cert_from_signer_info(p7, sign_info);
x509 = NULL;
if (1 == PKCS7_verify(p7, NULL, NULL, p7bio, NULL, PKCS7_NOVERIFY))
bSigAppr = true;
BIO_free(p7bio);
}
PKCS7_free(p7);
BIO_free(vin);
return bSigAppr;
}
...
js
const FSDK = require("@foxitsoftware/foxit-pdf-sdk-node");
...
let doc = new FSDK.PDFDoc("Sample.pdf");
csharp
using System;
using System.Runtime.InteropServices;
using foxit;
using foxit.common;
using foxit.common.fxcrt;
using foxit.pdf;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography;
using System.Text;
namespace signatureCS
{
class SignAndVerifyMsg
{
public static X509Certificate2 GetCertificate(string commonName, StoreName storeName)
{
X509Certificate2 certificate = null;
// Look for a certificate in the local machine store.
var store = new X509Store(storeName, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
foreach (var cert in store.Certificates)
{
var subjectNames = cert.SubjectName.Name.Split(',');
foreach (var subjectName in subjectNames)
{
string cn = " CN=" + commonName;
if (subjectName.Equals(cn))
{
certificate = cert;
break;
}
}
if (certificate != null)
{
break;
}
}
return certificate;
}
public static bool SignMsg(byte[] to_be_signed_data, string commonName, StoreName storeName, ref byte[] signed_data)
{
X509Certificate2 cert = GetCertificate(commonName, storeName);
if (cert == null)
{
cert = GetCertificate(commonName, StoreName.Root);
}
CmsSigner signer = new CmsSigner(cert);
signer.DigestAlgorithm = new Oid("1.3.14.3.2.26", "sha1");
signer.IncludeOption = X509IncludeOption.WholeChain;
ContentInfo signedData = new ContentInfo(to_be_signed_data);
SignedCms cms = new SignedCms(signedData, false);
cms.ComputeSignature(signer);
signed_data = cms.Encode();
return true;
}
public static bool VerifyMsg(byte[] verify_data, byte[] signed_data)
{
Boolean b = true;
try
{
ContentInfo signedData = new ContentInfo(verify_data);
SignedCms cms = new SignedCms(signedData, false);
cms.Decode(signed_data);
// Check Signature
cms.CheckSignature(true);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
b = false;
}
return b;
}
}
// Used for implementing SignatureCallback.
class DigestContext
{
public FileReaderCallback file_read_callback_;
public System.IntPtr byte_range_array_;
public int byte_range_array_size_;
public DigestContext(FileReaderCallback file_read_callback, System.IntPtr byte_range_array, int byte_range_array_size)
{
this.file_read_callback_ = file_read_callback;
this.byte_range_array_ = byte_range_array;
this.byte_range_array_size_ = byte_range_array_size;
}
};
// Implementation of pdf::SignatureCallback
class SignatureCallbackImpl : SignatureCallback
{
private DigestContext digest_context_ = null;
byte[] arrall = null;
public SignatureCallbackImpl()
{
}
public override bool StartCalcDigest(FileReaderCallback file, System.IntPtr byte_range_array, int size_of_array, Signature signature, IntPtr client_data)
{
digest_context_ = new DigestContext(file, byte_range_array, size_of_array);
return true;
}
public override Progressive.State ContinueCalcDigest(IntPtr client_data, PauseCallback pause)
{
FileReaderCallback filehandler = digest_context_.file_read_callback_;
int[] int_array = new int[digest_context_.byte_range_array_size_];
Marshal.Copy(digest_context_.byte_range_array_, int_array, 0, digest_context_.byte_range_array_size_);
byte[] arr1 = new byte[int_array[1]];
IntPtr buffer1 = Marshal.AllocHGlobal(int_array[1]);
filehandler.ReadBlock(buffer1,
int_array[0],
(uint)int_array[1]);
Marshal.Copy(buffer1, arr1, 0, int_array[1]);
byte[] arr2 = new byte[int_array[3]];
IntPtr buffer2 = Marshal.AllocHGlobal(int_array[3]);
filehandler.ReadBlock(buffer2,
int_array[2],
(uint)int_array[3]);
Marshal.Copy(buffer2, arr2, 0, int_array[3]);
byte[] arrall_temp = new byte[(int)int_array[1]
+ (int)int_array[3]];
Array.Copy(arr1, 0, arrall_temp, 0, arr1.Length);
Array.Copy(arr2, 0, arrall_temp, arr1.Length, arr2.Length);
Marshal.FreeHGlobal(buffer1);
Marshal.FreeHGlobal(buffer2);
HashAlgorithm hash = HashAlgorithm.Create("sha1");
hash.Initialize();
arrall = hash.ComputeHash(arrall_temp);
return Progressive.State.e_Finished;
}
public override byte[] GetDigest(IntPtr client_data)
{
if (arrall != null)
{
return arrall;
}
return null;
}
public override byte[] Sign(IntPtr digest, int digest_length, string cert_path, byte[] password, Signature.DigestAlgorithm digest_algorithm, IntPtr client_data)
{
byte[] byte_digest = new byte[digest_length];
Marshal.Copy(digest, byte_digest, 0, digest_length);
byte[] encryptStr = null;
SignAndVerifyMsg.SignMsg(byte_digest, "test", StoreName.My, ref encryptStr);
return encryptStr;
}
public override byte[] Sign(IntPtr digest, int digest_length, StreamCallback cert_path, byte[] password, Signature.DigestAlgorithm digest_algorithm, IntPtr client_data)
{
return null;
}
public override uint VerifySigState(global::System.IntPtr digest, int digest_length, global::System.IntPtr signed_data, int signed_data_len, global::System.IntPtr client_data)
{
byte[] byte_signdata = new byte[signed_data_len];
Marshal.Copy(signed_data, byte_signdata, 0, signed_data_len);
byte[] byte_digest = new byte[digest_length];
Marshal.Copy(digest, byte_digest, 0, digest_length);
bool verified = SignAndVerifyMsg.VerifyMsg(byte_digest, byte_signdata);
return verified ? Convert.ToUInt32(Signature.States.e_StateVerifyNoChange) : Convert.ToUInt32(Signature.States.e_StateVerifyChange);
}
public override void Dispose()
{
}
public override void Release()
{
}
public override bool IsNeedPadData() { return false; }
public override SignatureCallback.CertValidity CheckCertificateValidity(string cert_path, byte[] cert_password, global::System.IntPtr client_data)
{
// User can check the validity of input certificate here.
// If no need to check, just return e_CertValid.
return SignatureCallback.CertValidity.e_CertValid;
}
}
class signature
{
private const string input_path = "../input_files/";
private const string output_path = "../output_files/pdf2office/";
static foxit.common.DateTime GetLocalDateTime()
{
System.DateTimeOffset rime = System.DateTimeOffset.Now;
foxit.common.DateTime datetime = new foxit.common.DateTime();
datetime.year = (UInt16)rime.Year;
datetime.month = (UInt16)rime.Month;
datetime.day = (ushort)rime.Day;
datetime.hour = (UInt16)rime.Hour;
datetime.minute = (UInt16)rime.Minute;
datetime.second = (UInt16)rime.Second;
datetime.utc_hour_offset = (short)rime.Offset.Hours;
datetime.utc_minute_offset = (ushort)rime.Offset.Minutes;
return datetime;
}
static Signature AddSiganture(PDFPage pdf_page, string sub_filter)
{
float page_height = pdf_page.GetHeight();
float page_width = pdf_page.GetWidth();
RectF new_sig_rect = new RectF(0, (float)(page_height * 0.9), (float)(page_width * 0.4), page_height);
// Add a new signature to page.
Signature new_sig = pdf_page.AddSignature(new_sig_rect);
if (new_sig.IsEmpty()) return null;
// Set values for the new signature.
new_sig.SetKeyValue(Signature.KeyName.e_KeyNameSigner, "Foxit PDF SDK");
String new_value = String.Format("As a sample for subfilter \"{0}\"", sub_filter);
new_sig.SetKeyValue(Signature.KeyName.e_KeyNameReason, new_value);
new_sig.SetKeyValue(Signature.KeyName.e_KeyNameContactInfo, "support@foxitsoftware.com");
new_sig.SetKeyValue(Signature.KeyName.e_KeyNameDN, "CN=CN,MAIL=MAIL@MAIL.COM");
new_sig.SetKeyValue(Signature.KeyName.e_KeyNameLocation, "Fuzhou, China");
new_value = String.Format("As a sample for subfilter \"{0}\"", sub_filter);
new_sig.SetKeyValue(Signature.KeyName.e_KeyNameText, new_value);
foxit.common.DateTime sign_time = GetLocalDateTime();
new_sig.SetSignTime(sign_time);
String image_file_path = input_path + "FoxitLogo.jpg";
using (Image image = new Image(image_file_path))
{
new_sig.SetImage(image, 0);
// Set appearance flags to decide which content would be used in appearance.
int ap_flags = Convert.ToInt32(Signature.APFlags.e_APFlagLabel | Signature.APFlags.e_APFlagSigner |
Signature.APFlags.e_APFlagReason | Signature.APFlags.e_APFlagDN |
Signature.APFlags.e_APFlagLocation | Signature.APFlags.e_APFlagText |
Signature.APFlags.e_APFlagSigningTime | Signature.APFlags.e_APFlagBitmap);
new_sig.SetAppearanceFlags(ap_flags);
}
return new_sig;
}
static SignatureCallbackImpl sig_callback = new SignatureCallbackImpl();
static void Main(string[] args)
{
System.IO.Directory.CreateDirectory(output_path);
string sn = " ";
string key = " ";
// Initialize library
ErrorCode error_code = Library.Initialize(sn, key);
if (error_code != ErrorCode.e_ErrSuccess)
{
if (ErrorCode.e_ErrInvalidLicense == error_code)
Console.WriteLine("[Failed] Current used Foxit PDF Conversion SDK key information is invalid.");
else
Console.WriteLine("Library Initialize Error: {0}", error_code);
return;
}
try
{
using (PDFDoc pdf_doc = new PDFDoc(input_path + "AboutFoxit.pdf"))
{
pdf_doc.StartLoad(null, true, null);
using (PDFPage pdf_page = pdf_doc.GetPage(0))
{
string filter = "Adobe.PPKLite";
string sub_filter = "adbe.pkcs7.sha1";
Library.RegisterSignatureCallback(filter, sub_filter, sig_callback);
// Add a new signature to first page.
using (Signature new_signature = AddSiganture(pdf_page, sub_filter))
{
new_signature.SetFilter(filter);
new_signature.SetSubFilter(sub_filter);
String signed_pdf_path = output_path + "signed_newsignature.pdf";
new_signature.StartSign("", Encoding.ASCII.GetBytes(""),
Signature.DigestAlgorithm.e_DigestSHA1, signed_pdf_path, IntPtr.Zero, null);
}
}
}
}
catch (PDFException e)
{
switch (e.GetErrorCode())
{
case ErrorCode.e_ErrNoPDF2OfficeModuleRight:
Console.WriteLine("[Failed] Conversion module is not contained in current Foxit PDF Conversion SDK keys.");
break;
default:
Console.WriteLine(e.Message);
break;
}
}
Library.Release();
}
}
}