我正在使用OpenSSL通过PoDoFo库为PDF生成数字签名。 这是签名处理程序的逻辑
OpenSSLSignatureHandler.h
#import <Foundation/Foundation.h>
// OpenSSL includes
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pkcs12.h>
#include <openssl/pkcs7.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
@interface OpenSSLSignatureHandler : NSObject
{
SHA_CTX m_sha_ctx;
EVP_PKEY* mp_pkey; // private key
X509* mp_x509; // signing certificate
STACK_OF(X509)* mp_ca; // certificate chain up to the CA
}
- (id) initWithCert:(NSString*) p12file password: (NSString*) password;
- (void) AppendData: (NSData*)data;
- (NSData*) getSignature;
@end
OpenSSLSignatureHandler.m
#import "OpenSSLSignatureHandler.h"
#include <string>
@implementation OpenSSLSignatureHandler
- (id) initWithCert:(NSString*) p12file password: (NSString*) password{
if (self = [super init]) {
// Initialize OpenSSL library
CRYPTO_malloc_init();
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
FILE* fp = fopen([p12file cStringUsingEncoding: NSASCIIStringEncoding], "rb");
if (fp == NULL)
@throw ([NSException exceptionWithName: @"PDFNet Exception" reason: @"Cannot open private key." userInfo: nil]);
PKCS12* p12 = d2i_PKCS12_fp(fp, NULL);
fclose(fp);
if (p12 == NULL)
@throw ([NSException exceptionWithName: @"PDFNet Exception" reason: @"Cannot parse private key." userInfo: nil]);
mp_pkey = NULL;
mp_x509 = NULL;
mp_ca = NULL;
int parseResult = PKCS12_parse(p12, [password cStringUsingEncoding: NSASCIIStringEncoding], &mp_pkey, &mp_x509, &mp_ca);
PKCS12_free(p12);
if (parseResult == 0)
@throw ([NSException exceptionWithName: @"PDFNet Exception" reason: @"Cannot parse private key." userInfo: nil]);
//initialize sha context
SHA1_Init(&m_sha_ctx);
}
return self;
}
- (void) AppendData: (NSData*)data
{
SHA1_Update(&m_sha_ctx, [data bytes], [data length]);
return;
}
- (BOOL) Reset
{
SHA1_Init(&m_sha_ctx);
return (YES);
}
- (NSData*) getSignature
{
unsigned char sha_buffer[SHA_DIGEST_LENGTH];
memset((void*) sha_buffer, 0, SHA_DIGEST_LENGTH);
SHA1_Final(sha_buffer, &m_sha_ctx);
PKCS7* p7 = PKCS7_new();
PKCS7_set_type(p7, NID_pkcs7_signed);
PKCS7_SIGNER_INFO* p7Si = PKCS7_add_signature(p7, mp_x509, mp_pkey, EVP_sha1());
PKCS7_add_attrib_content_type(p7Si, OBJ_nid2obj(NID_pkcs7_data));
PKCS7_add0_attrib_signing_time(p7Si, NULL);
PKCS7_add1_attrib_digest(p7Si, (const unsigned char*) sha_buffer, SHA_DIGEST_LENGTH);
PKCS7_add_certificate(p7, mp_x509);
int c = 0;
for ( ; c < sk_X509_num(mp_ca); c++) {
X509* cert = sk_X509_value(mp_ca, c);
PKCS7_add_certificate(p7, cert);
}
PKCS7_set_detached(p7, 1);
PKCS7_content_new(p7, NID_pkcs7_data);
PKCS7_SIGNER_INFO_sign(p7Si);
int p7Len = i2d_PKCS7(p7, NULL);
NSMutableData* signature = [NSMutableData data];
unsigned char* p7Buf = (unsigned char*) malloc(p7Len);
if (p7Buf != NULL) {
unsigned char* pP7Buf = p7Buf;
i2d_PKCS7(p7, &pP7Buf);
[signature appendBytes: (const void*) p7Buf length: p7Len];
free(p7Buf);
}
PKCS7_free(p7);
return (signature);
}
- (void) dealloc
{
sk_X509_free(mp_ca);
X509_free(mp_x509);
EVP_PKEY_free(mp_pkey);
// Release OpenSSL resource usage
ERR_free_strings();
EVP_cleanup();
[super dealloc];
}
@end
使用podofo嵌入签名
void CreateSimpleForm( PoDoFo::PdfPage* pPage, PoDoFo::PdfStreamedDocument* pDoc, const PoDoFo::PdfData &signatureData )
{
PoDoFo::PdfPainter painter;
PoDoFo::PdfFont* pFont = pDoc->CreateFont( "Courier" );
painter.SetPage( pPage );
painter.SetFont( pFont );
painter.DrawText( 10000 * CONVERSION_CONSTANT, 280000 * CONVERSION_CONSTANT, "PoDoFo Sign Test" );
painter.FinishPage();
PoDoFo::PdfSignatureField signField( pPage, PoDoFo::PdfRect( 0, 0, 0, 0 ), pDoc );
signField.SetFieldName("SignatureFieldName");
signField.SetSignature(signatureData);
signField.SetSignatureReason("Document verification");
// Set time of signing
signField.SetSignatureDate( PoDoFo::PdfDate() );
}
+(void)addDigitalSignatureOnPage:(NSInteger)pageIndex outpath:(NSString*)path/*doc:(PoDoFo::PdfMemDocument*)aDoc*/{
PoDoFo::PdfPage* pPage;
PoDoFo::PdfSignOutputDevice signer([path UTF8String]);
// Reserve space for signature
signer.SetSignatureSize(1024);
if([[NSFileManager defaultManager] fileExistsAtPath:path]){
PoDoFo::PdfStreamedDocument writer( &signer, PoDoFo::ePdfVersion_1_5 );
// Disable default appearance
writer.GetAcroForm(PoDoFo::ePdfCreateObject, PoDoFo::PdfAcroForm::ePdfAcroFormDefaultAppearance_None);
pPage = writer.CreatePage(PoDoFo::PdfPage::CreateStandardPageSize(PoDoFo::ePdfPageSize_A4 ) );
TEST_SAFE_OP( CreateSimpleForm( pPage, &writer, *signer.GetSignatureBeacon() ) );
TEST_SAFE_OP( writer.Close() );
}
// Check if position of signature was found
if(signer.HasSignaturePosition()) {
// Adjust ByteRange for signature
signer.AdjustByteRange();
// Read data for signature and count it
// We have to seek at the beginning of the file
signer.Seek(0);
//OpenSSLSignatureHandler
NSString * p12certpath = [[NSBundle mainBundle] pathForResource:@"iphone-cert" ofType:@"p12"];
OpenSSLSignatureHandler*signatureHandler = [[OpenSSLSignatureHandler alloc] initWithCert:p12certpath password:@"test123$"];
char buff[65536];
size_t len;
while( (len = signer.ReadForSignature(buff, 65536))>0 )
{
NSData* data = [NSData dataWithBytes:(const void *)buff length:len];
[signatureHandler AppendData:data];
}
const PoDoFo::PdfData *pSignature = NULL;
// NSString *pkcsMessage = [[signatureHandler getSignature] base64EncodedString];
// NSLog(@"OpenSSLSignatureHandler signature message = %@",pkcsMessage);
// const char * cstr = [pkcsMessage UTF8String];
// if(pSignature==NULL)pSignature = new PoDoFo::PdfData(cstr, sizeof(cstr));
unsigned char *bytePtr = (unsigned char *)[[signatureHandler getSignature] bytes];
std::string str;
str.append(reinterpret_cast<const char*>(bytePtr));
// Paste signature to the file
if(pSignature==NULL)pSignature = new PoDoFo::PdfData(str.c_str(), sizeof(str));
NSLog(@"str = %s",str.c_str());
NSLog(@"sizeof(str) = %lu",sizeof(str));
signer.SetSignature(*pSignature);
}
signer.Flush();
}
但是嵌入PDF中的签名总是空的
可以帮助解决这个问题吗?