File Coverage

xs/signature.xs
Criterion Covered Total %
statement 43 232 18.5
branch 30 234 12.8
condition n/a
subroutine n/a
pod n/a
total 73 466 15.6


line stmt bran cond sub pod time code
1             ##############################################################################
2             # Signature XS bindings
3             ##############################################################################
4              
5             MODULE = PDF::Make PACKAGE = PDF::Make::Signature
6             PROTOTYPES: ENABLE
7              
8             ##############################################################################
9             # Signature verification and counting
10             ##############################################################################
11              
12             SV *
13             _verify(data_sv, index)
14             SV *data_sv
15             int index
16             PREINIT:
17             STRLEN len;
18             const uint8_t *data;
19             pdfmake_arena_t *arena;
20             pdfmake_sig_verify_result_t *result;
21             HV *hv;
22             CODE:
23 4           data = (const uint8_t *)SvPVbyte(data_sv, len);
24            
25 4           arena = pdfmake_arena_new();
26 4 50         if (!arena)
27 0           croak("PDF::Make::Signature::_verify: out of memory");
28            
29 4           result = pdfmake_sig_verify(arena, data, len, index);
30            
31 4           hv = newHV();
32            
33 4 50         if (result) {
34 4           hv_store(hv, "valid", 5, newSViv(result->valid), 0);
35 4           hv_store(hv, "signature_valid", 15, newSViv(result->signature_valid), 0);
36 4           hv_store(hv, "digest_valid", 12, newSViv(result->digest_valid), 0);
37 4           hv_store(hv, "cert_valid", 10, newSViv(result->cert_valid), 0);
38 4           hv_store(hv, "timestamp_valid", 15, newSViv(result->timestamp_valid), 0);
39 4           hv_store(hv, "document_modified", 17, newSViv(result->document_modified), 0);
40            
41 4 50         if (result->signer_name)
42 0           hv_store(hv, "signer_name", 11, newSVpv(result->signer_name, 0), 0);
43 4 50         if (result->signer_email)
44 0           hv_store(hv, "signer_email", 12, newSVpv(result->signer_email, 0), 0);
45 4 50         if (result->signing_time > 0)
46 0           hv_store(hv, "signing_time", 12, newSViv(result->signing_time), 0);
47 4 50         if (result->error)
48 4           hv_store(hv, "error", 5, newSVpv(result->error, 0), 0);
49             } else {
50 0           hv_store(hv, "valid", 5, newSViv(0), 0);
51 0           hv_store(hv, "error", 5, newSVpv("Verification not implemented or no signature found", 0), 0);
52             }
53            
54 4           pdfmake_arena_free(arena);
55            
56             /* Return a PDF::Make::SignatureResult object */
57             {
58 4           SV *obj_ref = newRV_noinc((SV*)hv);
59 4           sv_bless(obj_ref, gv_stashpv("PDF::Make::SignatureResult", GV_ADD));
60 4           RETVAL = obj_ref;
61             }
62             OUTPUT:
63             RETVAL
64              
65             int
66             _count(data_sv)
67             SV *data_sv
68             PREINIT:
69             STRLEN len;
70             const uint8_t *data;
71             CODE:
72 4           data = (const uint8_t *)SvPVbyte(data_sv, len);
73 4           RETVAL = pdfmake_sig_count(data, len);
74             OUTPUT:
75             RETVAL
76              
77             ##############################################################################
78             # Hash functions
79             ##############################################################################
80              
81             SV *
82             _hash_sha256(data_sv)
83             SV *data_sv
84             PREINIT:
85             STRLEN len;
86             const uint8_t *data;
87             uint8_t digest[32];
88             size_t digest_len;
89             CODE:
90 0           data = (const uint8_t *)SvPVbyte(data_sv, len);
91 0           digest_len = pdfmake_hash(PDFMAKE_HASH_SHA256, data, len, digest);
92 0 0         if (digest_len == 0)
93 0           XSRETURN_UNDEF;
94 0           RETVAL = newSVpvn((const char *)digest, digest_len);
95             OUTPUT:
96             RETVAL
97              
98             SV *
99             _hash_sha384(data_sv)
100             SV *data_sv
101             PREINIT:
102             STRLEN len;
103             const uint8_t *data;
104             uint8_t digest[48];
105             size_t digest_len;
106             CODE:
107 0           data = (const uint8_t *)SvPVbyte(data_sv, len);
108 0           digest_len = pdfmake_hash(PDFMAKE_HASH_SHA384, data, len, digest);
109 0 0         if (digest_len == 0)
110 0           XSRETURN_UNDEF;
111 0           RETVAL = newSVpvn((const char *)digest, digest_len);
112             OUTPUT:
113             RETVAL
114              
115             SV *
116             _hash_sha512(data_sv)
117             SV *data_sv
118             PREINIT:
119             STRLEN len;
120             const uint8_t *data;
121             uint8_t digest[64];
122             size_t digest_len;
123             CODE:
124 0           data = (const uint8_t *)SvPVbyte(data_sv, len);
125 0           digest_len = pdfmake_hash(PDFMAKE_HASH_SHA512, data, len, digest);
126 0 0         if (digest_len == 0)
127 0           XSRETURN_UNDEF;
128 0           RETVAL = newSVpvn((const char *)digest, digest_len);
129             OUTPUT:
130             RETVAL
131              
132             ##############################################################################
133             # SigningIdentity - PKCS#12 and PEM parsing
134             ##############################################################################
135              
136             MODULE = PDF::Make PACKAGE = PDF::Make::SigningIdentity
137             PROTOTYPES: ENABLE
138              
139             pdfmake_signing_identity_t *
140             _from_pkcs12(class, data_sv, password)
141             const char *class
142             SV *data_sv
143             const char *password
144             PREINIT:
145             STRLEN len;
146             const uint8_t *data;
147             pdfmake_arena_t *arena;
148             CODE:
149             PERL_UNUSED_VAR(class);
150 1           data = (const uint8_t *)SvPVbyte(data_sv, len);
151            
152 1           arena = pdfmake_arena_new();
153 1 50         if (!arena)
154 0           croak("PDF::Make::SigningIdentity: out of memory");
155            
156 1           RETVAL = pdfmake_pkcs12_parse(arena, data, len, password);
157 1 50         if (!RETVAL) {
158 0           pdfmake_arena_free(arena);
159 0           croak("PDF::Make::SigningIdentity: failed to parse PKCS#12 data");
160             }
161             /* Note: arena is now owned by the identity */
162             OUTPUT:
163             RETVAL
164              
165             void
166             DESTROY(self_sv)
167             SV *self_sv
168             PREINIT:
169             SV *inner;
170             pdfmake_signing_identity_t *self;
171             CODE:
172             /* The PDF::Make::SigningIdentity package has two constructors:
173             * - XS: _from_pkcs12() blesses a scalar holding a native pointer
174             * - pure-Perl: ::new() in lib/PDF/Make/Signature.pm blesses a HASH
175             * Only the XS-created variant owns a pdfmake_signing_identity_t
176             * that must be freed here. Without this guard, calling SvIV on a
177             * blessed HASH at global destruction emits a spurious
178             * "Use of uninitialized value in subroutine entry" warning. */
179 2 50         if (sv_isobject(self_sv) && SvROK(self_sv)) {
    50          
180 2           inner = SvRV(self_sv);
181 2 50         if (inner && SvTYPE(inner) < SVt_PVAV) {
    100          
182 1           self = INT2PTR(pdfmake_signing_identity_t *, SvIV(inner));
183 1 50         if (self) pdfmake_signing_identity_free(self);
184             }
185             }
186              
187             int
188             has_private_key(self)
189             pdfmake_signing_identity_t *self
190             CODE:
191 1 50         RETVAL = (self && self->privkey != NULL);
    50          
    50          
192             OUTPUT:
193             RETVAL
194              
195             int
196             has_certificate(self)
197             pdfmake_signing_identity_t *self
198             CODE:
199 1 50         RETVAL = (self && self->cert != NULL);
    50          
    50          
200             OUTPUT:
201             RETVAL
202              
203             int
204             chain_length(self)
205             pdfmake_signing_identity_t *self
206             CODE:
207 1 50         if (!self || !self->chain)
    50          
208 1           RETVAL = 0;
209             else
210 0           RETVAL = self->chain->count;
211             OUTPUT:
212             RETVAL
213              
214             SV *
215             subject(self)
216             pdfmake_signing_identity_t *self
217             CODE:
218 1 50         if (!self || !self->cert || !self->cert->subject.dn)
    50          
    50          
219 0           XSRETURN_UNDEF;
220 1           RETVAL = newSVpv(self->cert->subject.dn, 0);
221             OUTPUT:
222             RETVAL
223              
224             SV *
225             issuer(self)
226             pdfmake_signing_identity_t *self
227             CODE:
228 1 50         if (!self || !self->cert || !self->cert->issuer.dn)
    50          
    50          
229 0           XSRETURN_UNDEF;
230 1           RETVAL = newSVpv(self->cert->issuer.dn, 0);
231             OUTPUT:
232             RETVAL
233              
234             SV *
235             serial(self)
236             pdfmake_signing_identity_t *self
237             CODE:
238 0 0         if (!self || !self->cert || !self->cert->serial_hex)
    0          
    0          
239 0           XSRETURN_UNDEF;
240 0           RETVAL = newSVpv(self->cert->serial_hex, 0);
241             OUTPUT:
242             RETVAL
243              
244             IV
245             not_before(self)
246             pdfmake_signing_identity_t *self
247             CODE:
248 0 0         if (!self || !self->cert)
    0          
249 0           RETVAL = 0;
250             else
251 0           RETVAL = self->cert->not_before;
252             OUTPUT:
253             RETVAL
254              
255             IV
256             not_after(self)
257             pdfmake_signing_identity_t *self
258             CODE:
259 0 0         if (!self || !self->cert)
    0          
260 0           RETVAL = 0;
261             else
262 0           RETVAL = self->cert->not_after;
263             OUTPUT:
264             RETVAL
265              
266             int
267             is_valid(self, ...)
268             pdfmake_signing_identity_t *self
269             PREINIT:
270             int64_t check_time;
271             CODE:
272 0 0         if (items > 1)
273 0           check_time = (int64_t)SvIV(ST(1));
274             else
275 0           check_time = 0; /* pdfmake_x509_is_valid handles 0 as "now" */
276            
277 0 0         if (!self || !self->cert)
    0          
278 0           RETVAL = 0;
279             else
280 0           RETVAL = pdfmake_x509_is_valid(self->cert, check_time);
281             OUTPUT:
282             RETVAL
283              
284             int
285             can_sign(self)
286             pdfmake_signing_identity_t *self
287             CODE:
288 1 50         if (!self || !self->cert)
    50          
289 0           RETVAL = 0;
290             else
291 1           RETVAL = pdfmake_x509_can_sign_documents(self->cert);
292             OUTPUT:
293             RETVAL
294              
295             const char *
296             algorithm(self)
297             pdfmake_signing_identity_t *self
298             CODE:
299 0 0         if (!self || !self->privkey)
    0          
300 0           RETVAL = "unknown";
301             else
302 0           RETVAL = pdfmake_x509_pk_algorithm_name(self->privkey->algorithm);
303             OUTPUT:
304             RETVAL
305              
306             ##############################################################################
307             # Certificate wrapper
308             ##############################################################################
309              
310             MODULE = PDF::Make PACKAGE = PDF::Make::CertificateXS
311             PROTOTYPES: ENABLE
312              
313             SV *
314             subject(self)
315             pdfmake_x509_cert_t *self
316             CODE:
317 0 0         if (!self || !self->subject.dn)
    0          
318 0           XSRETURN_UNDEF;
319 0           RETVAL = newSVpv(self->subject.dn, 0);
320             OUTPUT:
321             RETVAL
322              
323             SV *
324             issuer(self)
325             pdfmake_x509_cert_t *self
326             CODE:
327 0 0         if (!self || !self->issuer.dn)
    0          
328 0           XSRETURN_UNDEF;
329 0           RETVAL = newSVpv(self->issuer.dn, 0);
330             OUTPUT:
331             RETVAL
332              
333             IV
334             version(self)
335             pdfmake_x509_cert_t *self
336             CODE:
337 0 0         RETVAL = self ? self->version : 0;
    0          
338             OUTPUT:
339             RETVAL
340              
341             int
342             is_ca(self)
343             pdfmake_x509_cert_t *self
344             CODE:
345 0 0         RETVAL = self ? self->is_ca : 0;
    0          
346             OUTPUT:
347             RETVAL
348              
349             int
350             is_self_signed(self)
351             pdfmake_x509_cert_t *self
352             CODE:
353 0 0         RETVAL = self ? self->is_self_signed : 0;
    0          
354             OUTPUT:
355             RETVAL
356              
357             int
358             can_sign_documents(self)
359             pdfmake_x509_cert_t *self
360             CODE:
361 0 0         RETVAL = self ? pdfmake_x509_can_sign_documents(self) : 0;
    0          
362             OUTPUT:
363             RETVAL
364              
365             int
366             is_valid(self, ...)
367             pdfmake_x509_cert_t *self
368             PREINIT:
369             int64_t check_time;
370             CODE:
371 0 0         if (items > 1)
372 0           check_time = (int64_t)SvIV(ST(1));
373             else
374 0           check_time = 0;
375 0 0         RETVAL = self ? pdfmake_x509_is_valid(self, check_time) : 0;
    0          
376             OUTPUT:
377             RETVAL
378              
379              
380              
381             MODULE = PDF::Make PACKAGE = PDF::Make::Signature
382              
383             SV *
384             _sign_doc(doc, identity, hash_alg, reason, location, contact, name, signing_time_sv, tst_token_sv, placeholder_sv, appearance_sv)
385             pdfmake_doc_t *doc
386             pdfmake_signing_identity_t *identity
387             int hash_alg
388             SV *reason
389             SV *location
390             SV *contact
391             SV *name
392             SV *signing_time_sv
393             SV *tst_token_sv
394             SV *placeholder_sv
395             SV *appearance_sv
396             PREINIT:
397             pdfmake_sig_config_t config;
398             pdfmake_buf_t out;
399 0           STRLEN tst_len = 0;
400 0           const uint8_t *tst_bytes = NULL;
401             /* Appearance-local storage: the HV* fields point into SVs owned by
402             * the caller's hashref; we only need these local char** arrays for
403             * the duration of the pdfmake_doc_sign call. */
404 0           char **ap_names = NULL;
405 0           char **ap_bases = NULL;
406 0           size_t ap_font_count = 0;
407 0           char **ap_xo_names = NULL;
408 0           uint32_t *ap_xo_nums = NULL;
409 0           size_t ap_xo_count = 0;
410             CODE:
411 0           pdfmake_sig_config_init(&config);
412 0           config.identity = identity;
413 0           config.hash_algorithm = (pdfmake_hash_algorithm_t)hash_alg;
414 0 0         if (SvOK(reason)) config.reason = SvPV_nolen(reason);
415 0 0         if (SvOK(location)) config.location = SvPV_nolen(location);
416 0 0         if (SvOK(contact)) config.contact_info = SvPV_nolen(contact);
417 0 0         if (SvOK(name)) config.name = SvPV_nolen(name);
418 0 0         if (SvOK(signing_time_sv)) config.signing_time = (int64_t)SvIV(signing_time_sv);
419 0 0         if (SvOK(tst_token_sv)) {
420 0           tst_bytes = (const uint8_t *)SvPVbyte(tst_token_sv, tst_len);
421 0           config.tst_token = tst_bytes;
422 0           config.tst_token_len = (size_t)tst_len;
423             }
424 0 0         if (SvOK(placeholder_sv)) {
425 0           config.placeholder_size = (size_t)SvUV(placeholder_sv);
426             }
427             /* appearance_sv: hashref with optional keys
428             * visible => bool
429             * page => int (1-based)
430             * rect => [x0, y0, x1, y1]
431             * stream => bytes (raw PDF content operators)
432             * fonts => { "Resource-name" => "BaseFont-name", ... }
433             * show_name / show_date / show_reason => bool
434             */
435 0 0         if (SvOK(appearance_sv) && SvROK(appearance_sv) &&
    0          
436 0 0         SvTYPE(SvRV(appearance_sv)) == SVt_PVHV) {
437 0           HV *ap = (HV *)SvRV(appearance_sv);
438             SV **v;
439 0 0         if ((v = hv_fetchs(ap, "visible", 0)) && SvTRUE(*v)) config.visible = 1;
    0          
440 0 0         if ((v = hv_fetchs(ap, "page", 0)) && SvOK(*v)) config.page = SvIV(*v);
    0          
441 0 0         if ((v = hv_fetchs(ap, "rect", 0)) && SvROK(*v) &&
    0          
442 0 0         SvTYPE(SvRV(*v)) == SVt_PVAV) {
443 0           AV *r = (AV *)SvRV(*v);
444 0 0         for (int i = 0; i < 4 && i <= av_len(r); i++) {
    0          
445 0           SV **e = av_fetch(r, i, 0);
446 0 0         if (e && SvOK(*e)) config.rect[i] = SvNV(*e);
    0          
447             }
448             }
449 0 0         if ((v = hv_fetchs(ap, "stream", 0)) && SvOK(*v)) {
    0          
450             STRLEN sl;
451 0           config.appearance_stream = (const uint8_t *)SvPVbyte(*v, sl);
452 0           config.appearance_stream_len = (size_t)sl;
453             }
454 0 0         if ((v = hv_fetchs(ap, "show_name", 0)) && SvOK(*v)) config.ap_show_name = SvTRUE(*v) ? 1 : 0;
    0          
455 0 0         if ((v = hv_fetchs(ap, "show_date", 0)) && SvOK(*v)) config.ap_show_date = SvTRUE(*v) ? 1 : 0;
    0          
456 0 0         if ((v = hv_fetchs(ap, "show_reason", 0)) && SvOK(*v)) config.ap_show_reason = SvTRUE(*v) ? 1 : 0;
    0          
457              
458 0 0         if ((v = hv_fetchs(ap, "fonts", 0)) && SvROK(*v) &&
    0          
459 0 0         SvTYPE(SvRV(*v)) == SVt_PVHV) {
460 0           HV *fh = (HV *)SvRV(*v);
461             I32 keylen;
462             char *key;
463             SV *val;
464 0           hv_iterinit(fh);
465 0 0         while ((val = hv_iternextsv(fh, &key, &keylen))) ap_font_count++;
466 0 0         if (ap_font_count > 0) {
467 0           ap_names = (char **)calloc(ap_font_count, sizeof(char *));
468 0           ap_bases = (char **)calloc(ap_font_count, sizeof(char *));
469 0           size_t i = 0;
470 0           hv_iterinit(fh);
471 0 0         while ((val = hv_iternextsv(fh, &key, &keylen))) {
472 0 0         if (!SvOK(val)) continue;
473 0           ap_names[i] = strndup(key, (size_t)keylen);
474 0           ap_bases[i] = strdup(SvPV_nolen(val));
475 0           i++;
476             }
477 0           config.appearance_font_count = i;
478 0           config.appearance_font_names = (const char **)ap_names;
479 0           config.appearance_font_bases = (const char **)ap_bases;
480             }
481             }
482              
483             /* xobjects => { "Im1" => 7, "Im2" => 11, ... } — already-added
484             * indirect object numbers referenced from the appearance stream.
485             * Used e.g. for embedding a scanned scribbled-signature PNG. */
486 0 0         if ((v = hv_fetchs(ap, "xobjects", 0)) && SvROK(*v) &&
    0          
487 0 0         SvTYPE(SvRV(*v)) == SVt_PVHV) {
488 0           HV *xh = (HV *)SvRV(*v);
489             I32 keylen;
490             char *key;
491             SV *val;
492 0           hv_iterinit(xh);
493 0 0         while ((val = hv_iternextsv(xh, &key, &keylen))) ap_xo_count++;
494 0 0         if (ap_xo_count > 0) {
495 0           ap_xo_names = (char **)calloc(ap_xo_count, sizeof(char *));
496 0           ap_xo_nums = (uint32_t *)calloc(ap_xo_count, sizeof(uint32_t));
497 0           size_t i = 0;
498 0           hv_iterinit(xh);
499 0 0         while ((val = hv_iternextsv(xh, &key, &keylen))) {
500 0 0         if (!SvOK(val)) continue;
501 0           ap_xo_names[i] = strndup(key, (size_t)keylen);
502 0           ap_xo_nums[i] = (uint32_t)SvUV(val);
503 0           i++;
504             }
505 0           config.appearance_xobject_count = i;
506 0           config.appearance_xobject_names = (const char **)ap_xo_names;
507 0           config.appearance_xobject_nums = ap_xo_nums;
508             }
509             }
510             }
511              
512 0           pdfmake_buf_init(&out);
513 0           pdfmake_err_t err = pdfmake_doc_sign(doc, &config, &out);
514             /* Free the font name/base allocations regardless of outcome. */
515 0 0         if (ap_xo_names) {
516 0 0         for (size_t i = 0; i < ap_xo_count; i++) free(ap_xo_names[i]);
517 0           free(ap_xo_names);
518 0           free(ap_xo_nums);
519             }
520 0 0         if (ap_names) {
521 0 0         for (size_t i = 0; i < ap_font_count; i++) {
522 0           free(ap_names[i]);
523 0 0         if (ap_bases) free(ap_bases[i]);
524             }
525 0           free(ap_names);
526 0           free(ap_bases);
527             }
528 0 0         if (err != PDFMAKE_OK) {
529 0           pdfmake_buf_free(&out);
530 0           croak("PDF::Make::Signature: signing failed (error %d)", err);
531             }
532              
533 0           RETVAL = newSVpvn((const char *)pdfmake_buf_data(&out), pdfmake_buf_len(&out));
534 0           pdfmake_buf_free(&out);
535             OUTPUT:
536             RETVAL
537              
538             SV *
539             _build_tsa_request(hash_alg, digest_sv, cert_req)
540             int hash_alg
541             SV *digest_sv
542             int cert_req
543             PREINIT:
544             pdfmake_arena_t *arena;
545             pdfmake_buf_t out;
546             STRLEN dlen;
547             const uint8_t *dbytes;
548             CODE:
549 0           dbytes = (const uint8_t *)SvPVbyte(digest_sv, dlen);
550 0           arena = pdfmake_arena_new();
551 0 0         if (!arena) croak("PDF::Make::Signature::_build_tsa_request: arena alloc failed");
552 0           pdfmake_buf_init(&out);
553 0           pdfmake_err_t err = pdfmake_tsa_build_request(
554             arena, (pdfmake_hash_algorithm_t)hash_alg,
555             dbytes, (size_t)dlen, cert_req, &out);
556 0 0         if (err != PDFMAKE_OK) {
557 0           pdfmake_buf_free(&out);
558 0           pdfmake_arena_free(arena);
559 0           croak("PDF::Make::Signature::_build_tsa_request: failed (%d)", err);
560             }
561 0           RETVAL = newSVpvn((const char *)pdfmake_buf_data(&out), pdfmake_buf_len(&out));
562 0           pdfmake_buf_free(&out);
563 0           pdfmake_arena_free(arena);
564             OUTPUT:
565             RETVAL
566              
567             SV *
568             _parse_tsa_response(resp_sv)
569             SV *resp_sv
570             PREINIT:
571             pdfmake_arena_t *arena;
572             STRLEN rlen;
573             const uint8_t *rbytes;
574 0           const uint8_t *token = NULL;
575 0           size_t token_len = 0;
576             int rc;
577             CODE:
578 0           rbytes = (const uint8_t *)SvPVbyte(resp_sv, rlen);
579 0           arena = pdfmake_arena_new();
580 0 0         if (!arena) croak("PDF::Make::Signature::_parse_tsa_response: arena alloc failed");
581 0           rc = pdfmake_tsa_parse_response(arena, rbytes, (size_t)rlen,
582             &token, &token_len);
583 0 0         if (rc == -2) {
584 0           pdfmake_arena_free(arena);
585 0           croak("PDF::Make::Signature::_parse_tsa_response: TSA rejected request");
586             }
587 0 0         if (rc != 0 || !token) {
    0          
588 0           pdfmake_arena_free(arena);
589 0           croak("PDF::Make::Signature::_parse_tsa_response: malformed response");
590             }
591 0           RETVAL = newSVpvn((const char *)token, token_len);
592 0           pdfmake_arena_free(arena);
593             OUTPUT:
594             RETVAL
595              
596             SV *
597             _extract_cms_signature(cms_sv)
598             SV *cms_sv
599             PREINIT:
600             pdfmake_arena_t *arena;
601             STRLEN clen;
602             const uint8_t *cbytes;
603 0           const uint8_t *sig = NULL;
604 0           size_t sig_len = 0;
605             CODE:
606 0           cbytes = (const uint8_t *)SvPVbyte(cms_sv, clen);
607 0           arena = pdfmake_arena_new();
608 0 0         if (!arena) croak("PDF::Make::Signature::_extract_cms_signature: arena alloc failed");
609 0 0         if (pdfmake_cms_extract_signature(arena, cbytes, (size_t)clen,
610 0 0         &sig, &sig_len) != 0 || !sig) {
611 0           pdfmake_arena_free(arena);
612 0           croak("PDF::Make::Signature::_extract_cms_signature: failed to parse CMS");
613             }
614 0           RETVAL = newSVpvn((const char *)sig, sig_len);
615 0           pdfmake_arena_free(arena);
616             OUTPUT:
617             RETVAL