File Coverage

SignCSR.xs
Criterion Covered Total %
statement 216 305 70.8
branch 95 210 45.2
condition n/a
subroutine n/a
pod n/a
total 311 515 60.3


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5              
6             #include
7             #include
8              
9             #include "ppport.h"
10              
11             #include
12             #include
13             #include
14             #include
15             #include
16             #include
17             #include
18             #include
19             #include
20             #include
21             #include
22             #include
23             #include
24              
25             # define OPT_FMT_PEM (1L << 1)
26             # define CHECK_OPEN_SSL(p_result) if (!(p_result)) croakSsl(__FILE__, __LINE__);
27             # define EXT_COPY_NONE 0
28             # define EXT_COPY_ADD 1
29             # define EXT_COPY_ALL 2
30             # define EXT_COPY_UNSET -1
31             # define SERIAL_RAND_BITS 159
32              
33             BIO *bio_err;
34             #if OPENSSL_API_COMPAT >= 30000
35             OSSL_LIB_CTX *libctx = NULL;
36             static const char *propq = NULL;
37             #endif
38             static unsigned long nmflag = 0;
39             static char nmflag_set = 0;
40              
41             // Taken from p5-Git-Raw
42 3           STATIC HV *ensure_hv(SV *sv, const char *identifier) {
43 3 50         if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVHV)
    50          
44 0           croak("Invalid type for '%s', expected a hash", identifier);
45              
46 3           return (HV *) SvRV(sv);
47             }
48              
49 3           int rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
50             {
51             BIGNUM *btmp;
52 3           int ret = 0;
53              
54 3 50         btmp = b == NULL ? BN_new() : b;
55 3 50         if (btmp == NULL)
56 0           return 0;
57              
58             #if OPENSSL_API_COMPAT <= 10100
59 3 50         if (!BN_rand(btmp, SERIAL_RAND_BITS, 0, 0))
60             #else
61             if (!BN_rand(btmp, SERIAL_RAND_BITS, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY))
62             #endif
63 0           goto error;
64 3 50         if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
    50          
65 0           goto error;
66              
67 3           ret = 1;
68              
69 3           error:
70              
71 3 50         if (btmp != b)
72 3           BN_free(btmp);
73              
74 3           return ret;
75             }
76              
77 3           int set_cert_times(X509 *x, const char *startdate, const char *enddate,
78             int days)
79             {
80 3 50         if (startdate == NULL || strcmp(startdate, "today") == 0) {
    0          
81             #if OPENSSL_API_COMPAT <= 10100
82 3 50         if (X509_gmtime_adj(X509_get_notBefore(x), 0) == NULL)
83             #else
84             if (X509_gmtime_adj(X509_getm_notBefore(x), 0) == NULL)
85             #endif
86 0           return 0;
87             } else {
88             #if OPENSSL_API_COMPAT <= 11000
89 0 0         if (!ASN1_TIME_set_string(X509_get_notBefore(x), startdate))
90             #else
91             if (!ASN1_TIME_set_string_X509(X509_getm_notBefore(x), startdate))
92             #endif
93 0           return 0;
94             }
95 3 50         if (enddate == NULL) {
96             #if OPENSSL_API_COMPAT <= 10100
97 3 50         if (X509_time_adj_ex(X509_get_notAfter(x), days, 0, NULL)
98             #else
99             if (X509_time_adj_ex(X509_getm_notAfter(x), days, 0, NULL)
100             #endif
101             == NULL)
102 0           return 0;
103             #if OPENSSL_API_COMPAT <= 11000
104 0 0         } else if (!ASN1_TIME_set_string(X509_get_notAfter(x), enddate)) {
105             #else
106             } else if (!ASN1_TIME_set_string_X509(X509_getm_notAfter(x), enddate)) {
107             #endif
108 0           return 0;
109             }
110 3           return 1;
111             }
112              
113 3           int copy_extensions(X509 *x, X509_REQ *req, int copy_type)
114             {
115             STACK_OF(X509_EXTENSION) *exts;
116 3           int i, ret = 0;
117              
118 3 50         if (x == NULL || req == NULL)
    50          
119 0           return 0;
120 3 50         if (copy_type == EXT_COPY_NONE)
121 0           return 1;
122 3           exts = X509_REQ_get_extensions(req);
123              
124 13 100         for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
125 10           X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
126 10           ASN1_OBJECT *obj = X509_EXTENSION_get_object(ext);
127 10           int idx = X509_get_ext_by_OBJ(x, obj, -1);
128              
129             /* Does extension exist in target? */
130 10 50         if (idx != -1) {
131             /* If normal copy don't override existing extension */
132 0 0         if (copy_type == EXT_COPY_ADD)
133 0           continue;
134             /* Delete all extensions of same type */
135             do {
136 0           X509_EXTENSION_free(X509_delete_ext(x, idx));
137 0           idx = X509_get_ext_by_OBJ(x, obj, -1);
138 0 0         } while (idx != -1);
139             }
140 10 50         if (!X509_add_ext(x, ext, -1))
141 0           goto end;
142             }
143 3           ret = 1;
144              
145 3           end:
146 3           sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
147 3           return ret;
148             }
149              
150 3           int cert_matches_key(const X509 *cert, const EVP_PKEY *pkey)
151             {
152             int match;
153              
154 3           ERR_set_mark();
155 3           match = X509_check_private_key((X509 *) cert, (EVP_PKEY *) pkey);
156 3           ERR_pop_to_mark();
157 3           return match;
158             }
159              
160 3           static int do_x509_req_init(X509_REQ *x, STACK_OF(OPENSSL_STRING) *opts)
161             {
162             //int i;
163              
164 3           opts = NULL;
165 3 50         if (opts == NULL)
166 3           return 1;
167              
168             //for (i = 0; i < sk_OPENSSL_STRING_num(opts); i++) {
169             // char *opt = sk_OPENSSL_STRING_value(opts, i);
170              
171             // if (x509_req_ctrl_string(x, opt) <= 0) {
172             // croak("parameter error "); //$, n", opt);
173             // ERR_print_errors(bio_err);
174             // return 0;
175             // }
176             //}
177              
178 0           return 1;
179             }
180              
181             /*
182             * do_X509_REQ_verify returns 1 if the signature is valid,
183             * 0 if the signature check fails, or -1 if error occurs.
184             */
185 3           int do_X509_REQ_verify(X509_REQ *x, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *vfyopts)
186             {
187 3           int rv = 0;
188              
189 3 50         if (do_x509_req_init(x, vfyopts) > 0){
190             #if OPENSSL_API_COMPAT >= 30000
191             rv = X509_REQ_verify_ex(x, pkey, libctx, propq);
192             #else
193 3           rv = X509_REQ_verify(x, pkey);
194             #endif
195             }
196             else
197 0           rv = -1;
198 3           return rv;
199             }
200              
201 0           void croakSsl(char* p_file, int p_line)
202             {
203             const char* errorReason;
204             /* Just return the top error on the stack */
205 0           errorReason = ERR_reason_error_string(ERR_get_error());
206 0           ERR_clear_error();
207 0           croak("%s:%d: OpenSSL error: %s", p_file, p_line, errorReason);
208             }
209              
210 3           SV* extractBioString(pTHX_ BIO* p_stringBio)
211             {
212             SV* sv;
213             BUF_MEM* bptr;
214              
215 3 50         CHECK_OPEN_SSL(BIO_flush(p_stringBio) == 1);
216 3           BIO_get_mem_ptr(p_stringBio, &bptr);
217 3           sv = newSVpv(bptr->data, bptr->length);
218              
219 3 50         CHECK_OPEN_SSL(BIO_set_close(p_stringBio, BIO_CLOSE) == 1);
220 3           BIO_free(p_stringBio);
221 3           return sv;
222             }
223              
224 0           int pkey_ctrl_string(EVP_PKEY_CTX *ctx, const char *value)
225             {
226 0           int rv = 0;
227 0           char *stmp, *vtmp = NULL;
228              
229 0           stmp = OPENSSL_strdup(value);
230 0 0         if (stmp == NULL)
231 0           return -1;
232 0           vtmp = strchr(stmp, ':');
233 0 0         if (vtmp == NULL)
234 0           goto err;
235              
236 0           *vtmp = 0;
237 0           vtmp++;
238 0           rv = EVP_PKEY_CTX_ctrl_str(ctx, stmp, vtmp);
239              
240 0           err:
241 0           OPENSSL_free(stmp);
242 0           return rv;
243             }
244              
245 3           static int do_pkey_ctx_init(EVP_PKEY_CTX *pkctx, STACK_OF(OPENSSL_STRING) *opts)
246             {
247             int i;
248              
249 3 50         if (opts == NULL)
250 3           return 1;
251              
252 0 0         for (i = 0; i < sk_OPENSSL_STRING_num(opts); i++) {
253 0           char *opt = sk_OPENSSL_STRING_value(opts, i);
254              
255 0 0         if (pkey_ctrl_string(pkctx, opt) <= 0) {
256 0           BIO_printf(bio_err, "parameter error \"%s\"\n", opt);
257 0           ERR_print_errors(bio_err);
258 0           return 0;
259             }
260             }
261              
262 0           return 1;
263             }
264              
265 0           unsigned long get_nameopt(void)
266             {
267             return
268 0 0         nmflag_set ? nmflag : XN_FLAG_SEP_CPLUS_SPC | ASN1_STRFLGS_UTF8_CONVERT;
269             }
270              
271             #if OPENSSL_API_COMPAT >= 30101
272             static int do_sign_init(EVP_MD_CTX *ctx, EVP_PKEY *pkey, const char *md, STACK_OF(OPENSSL_STRING) *sigopts)
273             #else
274 3           static int do_sign_init(EVP_MD_CTX *ctx, EVP_PKEY *pkey, const EVP_MD *md, STACK_OF(OPENSSL_STRING) *sigopts)
275             #endif
276             {
277 3           EVP_PKEY_CTX *pkctx = NULL;
278             #if OPENSSL_API_COMPAT >= 30101
279             char def_md[80];
280             #else
281             int def_nid;
282             #endif
283              
284 3 50         if (ctx == NULL)
285 0           return 0;
286             /*
287             * EVP_PKEY_get_default_digest_name() returns 2 if the digest is mandatory
288             * for this algorithm.
289             */
290             #if OPENSSL_API_COMPAT >= 30101
291             if (EVP_PKEY_get_default_digest_name(pkey, def_md, sizeof(def_md)) == 2
292             && strcmp(def_md, "UNDEF") == 0) {
293             #else
294 3 50         if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) == 2
295 0 0         && def_nid == NID_undef) {
296             #endif
297             /* The signing algorithm requires there to be no digest */
298 0           md = NULL;
299             }
300              
301             #if OPENSSL_API_COMPAT >= 30101
302             int val = EVP_DigestSignInit_ex(ctx, &pkctx, md, libctx,
303             propq, pkey, NULL);
304             #else
305 3           int val = EVP_DigestSignInit(ctx, &pkctx, md, NULL, pkey);
306             #endif
307             return val
308 3 50         && do_pkey_ctx_init(pkctx, sigopts);
    50          
309             }
310              
311 3           static int key_destroy(pTHX_ SV* var, MAGIC* magic) {
312             EVP_PKEY * key;
313              
314 3           key = (EVP_PKEY *) magic->mg_ptr;
315 3 50         if (!key)
316 0           return 0;
317              
318 3           EVP_PKEY_free(key);
319 3           return 1;
320             }
321              
322             static const MGVTBL key_magic = { NULL, NULL, NULL, NULL, key_destroy };
323              
324              
325             MODULE = Crypt::OpenSSL::SignCSR PACKAGE = Crypt::OpenSSL::SignCSR PREFIX = signcsr_
326              
327             BOOT:
328 3           ERR_load_crypto_strings();
329             #if OPENSSL_API_COMPAT <= 10100
330 3           ERR_load_ERR_strings();
331 3           OpenSSL_add_all_algorithms();
332 3           OpenSSL_add_all_ciphers();
333 3           OpenSSL_add_all_digests();
334             #endif
335              
336             PROTOTYPES: DISABLE
337              
338             SV * new(class, ...)
339             const char * class
340              
341             PREINIT:
342 3           SV * private_key = NULL;
343 3           HV * options = newHV();
344              
345             CODE:
346             STRLEN keyStringLength;
347             char* keyString;
348             BIO *bio;
349 3           SV * key = newSV(0);
350             SV **svp; // Temporary storage of options
351 3           SV *digest = NULL;
352 3           SV *format = newSVpv("pem", 3);
353 3           IV days = 365;
354              
355 3 50         if (items > 1) {
356 3 50         if (ST(1) != NULL) {
357             // TODO: ensure_string_sv
358 3           private_key = ST(1);
359 3 50         if (strlen(SvPV_nolen(private_key)) == 0) {
360 0           private_key = NULL;
361             }
362             }
363              
364 3 50         if (items > 2)
365 3           options = ensure_hv(ST(2), "options");
366             }
367              
368             // Get the number of days for specified - default 365
369 3 50         if (hv_exists(options, "days", strlen("days"))) {
370 3           svp = hv_fetch(options, "days", strlen("days"), 0);
371 3 50         if (SvIOKp(*svp)) {
372 3           days = SvIV(*svp);
373             }
374             }
375              
376             // Get the digest format - default NULL uses the openssl default
377 3 50         if (hv_exists(options, "digest", strlen("digest"))) {
378 3           svp = hv_fetch(options, "digest", strlen("digest"), 0);
379 3 50         if (SvPOKp(*svp)) {
380 3           digest = *svp;
381             }
382             } // No defaut value - sign will use openssl default
383              
384             // Get the output format - default is pem format
385 3 50         if (hv_exists(options, "format", strlen("format"))) {
386 3           svp = hv_fetch(options, "format", strlen("format"), 0);
387 3 50         if (SvPOKp(*svp)) {
388 3           format = *svp;
389             }
390             }
391              
392 3 50         if (private_key == NULL)
393 0           croak("Crypt::OpenSSL::SignCSR->new requires a non-empty PEM private key");
394              
395             // Get the private key and save it in memory
396 3           keyString = SvPV(private_key, keyStringLength);
397 3           bio = BIO_new_mem_buf(keyString, keyStringLength);
398 3 50         if (bio == NULL) {
399 0           croak ("Bio is null **** \n");
400             }
401              
402             // Create the PrivateKey as EVP_PKEY
403 3           EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, 0, NULL);
404 3           BIO_free(bio);
405 3 50         if (pkey == NULL) {
406 0           croak("Failed operation error code %d\n", errno);
407             }
408              
409             // This uses "Magic" to hold the private key object
410             // so it can be accessed later
411 3           HV * attributes = newHV();
412              
413 3           sv_magicext(key, NULL, PERL_MAGIC_ext,
414             &key_magic, (const char *)pkey, 0);
415              
416 3 50         if((hv_store(attributes, "privkey", 7, key, 0)) == NULL)
417 0           croak("unable to init privkey store");
418              
419 3 50         if (format != NULL)
420 3 50         if((hv_store(attributes, "format", 6, newRV_inc(format), 0)) == NULL)
421 0           croak("unable to init format store");
422              
423 3 50         if (digest != NULL)
424 3 50         if((hv_store(attributes, "digest", 6, newRV_inc(digest), 0)) == NULL)
425 0           croak("unable to init digest store");
426              
427 3 50         if((hv_store(attributes, "days", 4, newSViv(days), 0)) == NULL)
428 0           croak("unable to init days store");
429              
430 3           SV *const self = newRV_noinc( (SV *)attributes );
431              
432 3           RETVAL = sv_bless( self, gv_stashpv( class, 0 ) );
433              
434             OUTPUT:
435              
436             RETVAL
437              
438             char * get_digest(self)
439             HV * self;
440              
441             CODE:
442             SV **svp;
443              
444 2           RETVAL = SvPV_nolen(newSVpv("",0));
445              
446             // Get the output format - default is pem format
447 2 50         if (hv_exists(self, "digest", strlen("digest"))) {
448 2           svp = hv_fetch(self, "digest", strlen("digest"), 0);
449 2 50         if (SvROK(*svp)) {
450 2           RETVAL = SvPV_nolen(SvRV(*svp));
451             }
452             }
453              
454             OUTPUT:
455              
456             RETVAL
457              
458             IV set_digest(self, SV* digest)
459             HV * self;
460              
461             CODE:
462 1           const char * digestname = NULL;
463             STRLEN digestname_length;
464              
465 1           RETVAL = 0;
466 1           const EVP_MD *md = NULL;
467              
468 1 50         if (digest != NULL) {
469 1           digestname = (const char*) SvPV(digest, digestname_length);
470             // printf("Digest Name: %s\n", digestname);
471 1           md = EVP_get_digestbyname(digestname);
472             }
473              
474 1 50         if (md != NULL) {
475 1 50         if((hv_store(self, "digest", 6, newRV_inc(digest), 0)) == NULL)
476 0           RETVAL = 0;
477             else
478 1           RETVAL = 1;
479             } else {
480             //printf("Can't change digets to %s\n", digestname);
481             }
482              
483             OUTPUT:
484              
485             RETVAL
486              
487             char * get_format(self)
488             HV * self;
489              
490             CODE:
491             SV **svp;
492              
493 2           RETVAL = SvPV_nolen(newSVpv("",0));
494              
495             // Get the output format - default is pem format
496 2 50         if (hv_exists(self, "format", strlen("format"))) {
497 2           svp = hv_fetch(self, "format", strlen("format"), 0);
498 2 50         if (SvROK(*svp)) {
499 2           RETVAL = SvPV_nolen(SvRV(*svp));
500             }
501             }
502              
503             OUTPUT:
504              
505             RETVAL
506              
507             IV set_format(self, SV* format)
508             HV * self;
509              
510             CODE:
511 1           RETVAL = 0;
512              
513 2           if (sv_cmp(format, newSVpv("pem", 0)) == 0 ||
514 1 0         sv_cmp(format, newSVpv("text", 0)) == 0 ||
515 0           sv_cmp(format, newSVpv("der", 0)) == 0
516             )
517             {
518 2 50         if((hv_store(self, "format", 6, newRV_inc(format), 0)) == NULL)
519 0           RETVAL = 0;
520             else
521 1           RETVAL = 1;
522             } else {
523 0           RETVAL = 0;
524             }
525              
526             OUTPUT:
527              
528             RETVAL
529              
530             IV get_days(self)
531             HV * self;
532              
533             CODE:
534             SV **svp;
535              
536 2           RETVAL = -1;
537             // Get the number of days for specified - default 365
538 2 50         if (hv_exists(self, "days", strlen("days"))) {
539 2           svp = hv_fetch(self, "days", strlen("days"), 0);
540 2 50         if (SvIOKp(*svp)) {
541 2           RETVAL = SvIV(*svp);
542             }
543             }
544              
545             OUTPUT:
546              
547             RETVAL
548              
549             IV set_days(self, IV days)
550             HV * self;
551              
552             CODE:
553 1           RETVAL = 0;
554              
555 1 50         if((hv_store(self, "days", 4, newSViv(days), 0)) == NULL)
556 0           RETVAL = 0;
557             else
558 1           RETVAL = 1;
559              
560             OUTPUT:
561              
562             RETVAL
563              
564             SV * sign(self, request_SV)
565             HV * self;
566             SV * request_SV;
567              
568             PREINIT:
569             EVP_MD_CTX *mctx;
570              
571             CODE:
572              
573             SV **svp;
574             MAGIC* mg;
575             EVP_PKEY *private_key;
576             X509_REQ * csr;
577 3           int rv = 0;
578             STRLEN request_length;
579             unsigned char* request;
580             BIO *csrbio;
581             const char * digestname;
582             STRLEN digestname_length;
583             IV days;
584 3           SV * digest = NULL;
585 3           SV * format = NULL;
586              
587 3 50         if (!hv_exists(self, "privkey", strlen("privkey")))
588 0           croak("privkey not found in self!\n");
589              
590 3           svp = hv_fetch(self, "privkey", strlen("privkey"), 0);
591              
592 3 50         if (!SvMAGICAL(*svp) || (mg = mg_findext(*svp, PERL_MAGIC_ext, &key_magic)) == NULL)
    50          
593 0           croak("privkey is invalid");
594              
595 3 50         if (!hv_exists(self, "days", strlen("days")))
596 0           croak("days not found in self!\n");
597              
598 3           svp = hv_fetch(self, "days", strlen("days"), 0);
599 3 50         if (SvIOKp(*svp)) {
600 3           days = SvIV(*svp);
601             }
602             else {
603 0           days = 365;
604             }
605              
606 3 50         if (hv_exists(self, "digest", strlen("digest"))) {
607 3           svp = hv_fetch(self, "digest", strlen("digest"), 0);
608 3 50         if (SvROK(*svp)) {
609 3           digest = SvRV(*svp);
610             }
611             }
612              
613             //printf("Digest: %s\n", (char *) SvPV_nolen(digest));
614              
615 3 50         if (!hv_exists(self, "format", strlen("format")))
616 0           croak("format not found in self!\n");
617              
618 3           svp = hv_fetch(self, "format", strlen("format"), 0);
619 3 50         if (SvROK(*svp)) {
620 3           format = SvRV(*svp);
621             }
622              
623 3           private_key = (EVP_PKEY *) mg->mg_ptr;
624              
625             // Get the request that was passed into the sign function
626 3           request = (unsigned char*) SvPV(request_SV, request_length);
627              
628             // Create the X509_REQ from the request
629 3           csrbio = BIO_new_mem_buf(request, request_length);
630 3 50         if (csrbio == NULL) {
631 0           croak ("Bio for CRS Request is null **** \n");
632             }
633 3           csr = PEM_read_bio_X509_REQ(csrbio, NULL, NULL, NULL);
634 3           BIO_free(csrbio);
635              
636 3 50         if (csr == NULL) {
637 0           croak ("PEM_read_bio_X509_REQ failed **** \n");
638             }
639              
640             // Verify the CSR is properly signed
641             EVP_PKEY *pkey;
642 3 50         if (csr != NULL) {
643             #if OPENSSL_API_COMPAT <= 10100
644 3           pkey = X509_REQ_get_pubkey(csr);
645             #else
646             pkey = X509_REQ_get0_pubkey(csr);
647             #endif
648 3 50         if (pkey == NULL)
649 0           croak ("Warning: unable to get public key from CSR\n");
650              
651 3           int ret = do_X509_REQ_verify(csr, pkey, NULL);
652 3 50         if (ret == 0)
653 0           croak ("Verification of CSR failed\n");
654 3 50         if ( ret < 0)
655 0           croak ("Warning: error while verifying CSR self-signature\n");
656             }
657             else
658 0           croak("Unable to properly parse the Certificate Signing Request\n");
659              
660             // Create a new certificate store
661             X509 * x;
662             #if OPENSSL_API_COMPAT >= 30101
663             if ((x = X509_new_ex(libctx, propq)) == NULL)
664             #else
665 3 50         if ((x = X509_new()) == NULL)
666             #endif
667 0           croak("X509_new_ex failed ...\n");
668              
669             // FIXME need to look at this
670 3           int ext_copy = EXT_COPY_UNSET;
671 3 50         if (!copy_extensions(x, csr, ext_copy))
672 0           croak("Unable to copy extensions\n");
673              
674             // Update the certificate with the CSR's subject name
675 3 50         if (!X509_set_subject_name(x, X509_REQ_get_subject_name(csr)))
676 0           croak("X509_set_subject_name cannot set subject name\n");
677              
678             // Update the certificate with the CSR's public key
679             #if OPENSSL_API_COMPAT <= 10100
680 3 50         if (!X509_set_pubkey(x, X509_REQ_get_pubkey(csr)))
681             #else
682             if (!X509_set_pubkey(x, X509_REQ_get0_pubkey(csr)))
683             #endif
684 0           croak("X509_set_pubkey cannot set public key\n");
685              
686             // FIXME need to look at this
687             //for (int i = X509_get_ext_count(x) - 1; i >= 0; i--) {
688             // X509_EXTENSION *ex = X509_get_ext(x, i);
689             // const char *sn = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ex)));
690              
691             // if (clrext || (ext_names != NULL && strstr(ext_names, sn) == NULL))
692             // X509_EXTENSION_free(X509_delete_ext(x, i));
693             //}
694              
695             // FIXME - this may need to change to support signing by different certificates
696 3 50         if (private_key != NULL && !cert_matches_key(x, private_key))
    50          
697 0           croak("cert_matches_key: signature key and public key of cert do not match\n");
698              
699             // Generate a serial number and update the certificate
700 3           ASN1_INTEGER *sno = ASN1_INTEGER_new();
701 3 50         if (sno == NULL || !rand_serial(NULL, sno))
    50          
702 0           croak ("Unable to get ASN1INTEGER or random_serial\n");
703              
704 3 50         if (sno != NULL && !X509_set_serialNumber(x, sno))
    50          
705 0           croak("X509_set_serialNumber cannot set serial number\n");
706             // X509_set_serialNumber() dups its argument; free our copy.
707 3           ASN1_INTEGER_free(sno);
708              
709 3           set_cert_times(x, NULL, NULL, (int) days);
710              
711             // Set the certificate's issuer based on the issuer's certificate
712             // In self-signed certificates it is the same issuer
713             // FIXME this needs to be fixed to support non-self-signed certificate
714 3           X509 * issuer_cert = x;
715 3 50         if (!X509_set_issuer_name(x, X509_get_subject_name(issuer_cert)))
716 0           croak("X509_set_issuer_name cannot set issuer name\n");
717              
718             // Create the X509 v3 extensions for the certificate
719             X509V3_CTX ext_ctx;
720              
721             // Set the certificate issuer from the private key
722             #if OPENSSL_API_COMPAT >= 30000
723             X509V3_set_ctx(&ext_ctx, issuer_cert, x, NULL, NULL, X509V3_CTX_REPLACE);
724             if (!X509V3_set_issuer_pkey(&ext_ctx, private_key))
725             croak("X509V3_set_issuer_pkey cannot set issuer private key\n");
726             #elif OPENSSL_API_COMPAT >= 10010
727             X509V3_set_ctx(&ext_ctx, issuer_cert, x, csr, NULL, X509V3_CTX_REPLACE);
728             #else
729 3           X509V3_set_ctx(&ext_ctx, issuer_cert, x, csr, NULL, 0);
730             #endif
731              
732             // Set the X509 version of the certificate
733             #if OPENSSL_API_COMPAT >= 30000
734             if (!X509_set_version(x, X509_VERSION_3))
735             #else
736 3 50         if (!X509_set_version(x, 2))
737             #endif
738 0           croak("X509_set_version cannot set version 3\n");
739              
740 3 50         if (digest != NULL)
741 3           digestname = (const char*) SvPV(digest, digestname_length);
742             else
743 0           digestname = NULL;
744             #if OPENSSL_API_COMPAT >= 30101
745             if (digestname != NULL) {
746             EVP_MD *probe = EVP_MD_fetch(libctx, digestname, propq);
747             if (probe == NULL)
748             digestname = NULL;
749             else
750             EVP_MD_free(probe);
751             }
752             #else
753 3           const EVP_MD *md = (digestname != NULL)
754 3 50         ? EVP_get_digestbyname(digestname) : NULL;
755             #endif
756             //printf ("DIGEST NAME = %s\n", digestname);
757             // Allocate and a new digest context for certificate signing
758             #if OPENSSL_API_COMPAT <= 10100
759 3           mctx = EVP_MD_CTX_create();
760             #else
761             mctx = EVP_MD_CTX_new();
762             #endif
763              
764             // Sign the new certificate
765             #if OPENSSL_API_COMPAT >= 30101
766             if (mctx != NULL && do_sign_init(mctx, private_key, digestname, NULL) > 0)
767             #else
768 3 50         if (mctx != NULL && do_sign_init(mctx, private_key, md, NULL) > 0)
    50          
769             #endif
770 3           rv = (X509_sign_ctx(x, mctx) > 0);
771              
772 3 50         if (rv == 0)
773 0           croak("X509_sign_ctx cannot sign the new certificate\n");
774              
775             // Prepare to output new certificate
776 3           BIO * out = BIO_new(BIO_s_mem());
777              
778             int i;
779 3 100         if (sv_cmp(format, newSVpv("pem", 0)) == 0){
780             // Output the PEM encoded certificate
781 2           i = PEM_write_bio_X509(out, x);}
782 1 50         else if (sv_cmp(format, newSVpv("der", 0)) == 0){
783 1           i = i2d_X509_bio(out, x);}
784             else
785             // Output the text format of the certificate
786 0           i = X509_print_ex(out, x, get_nameopt(), 0);
787              
788 3 50         if (!i)
789 0           croak("unable to output certificate data\n");
790              
791 3           RETVAL = extractBioString(aTHX_ out);
792             #if OPENSSL_API_COMPAT <= 10100
793 3           EVP_MD_CTX_destroy(mctx);
794             #else
795             EVP_MD_CTX_free(mctx);
796             #endif
797 3           X509_REQ_free(csr);
798 3           X509_free(x);
799              
800             OUTPUT:
801              
802             RETVAL
803              
804             #if OPENSSL_API_COMPAT > 10200
805             void signcsr_DESTROY(void)
806              
807             CODE:
808             /* deinitialisation is done automatically */
809              
810             #else
811             void signcsr_DESTROY(void)
812              
813             CODE:
814              
815 3           CRYPTO_cleanup_all_ex_data();
816 3           ERR_free_strings();
817             #if OPENSSL_API_COMPAT < 10000
818 3           ERR_remove_state(0);
819             #endif
820 3           EVP_cleanup();
821              
822             #endif
823