1

我正在使用 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 中的签名始终为空

可以帮助解决这个问题吗?

4

0 回答 0