Crypt-OpenSSL-SignCSR

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN

NAME
    Crypt::OpenSSL::SignCSR - Sign a Certificate Signing Request in XS.

SYNOPSIS
      use Crypt::OpenSSL::SignCSR;

      my $signer = Crypt::OpenSSL::SignCSR->new(
                                    $private_key_pem
                                    {   # OPTIONAL
                                        days    => $days,   # Number of days for the certificate
                                        digest  => $digest, # Signature digest default (SHA256)
                                        format  => $format, # Output format "text" or "pem" (default)
                                    });
      my $cert   = $signer->sign(
                                    $request, # CSR in PEM format
                                );

      my $ret = $signer->set_days(3650);

SignCSR.xs  view on Meta::CPAN

 end:
    sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
    return ret;
}

int cert_matches_key(const X509 *cert, const EVP_PKEY *pkey)
{
    int match;

    ERR_set_mark();
    match = X509_check_private_key((X509 *) cert, (EVP_PKEY *) pkey);
    ERR_pop_to_mark();
    return match;
}

static int do_x509_req_init(X509_REQ *x, STACK_OF(OPENSSL_STRING) *opts)
{
    //int i;

    opts = NULL;
    if (opts == NULL)

SignCSR.xs  view on Meta::CPAN

    OpenSSL_add_all_ciphers();
    OpenSSL_add_all_digests();
#endif

PROTOTYPES: DISABLE

SV * new(class, ...)
    const char * class

    PREINIT:
        SV * private_key = NULL;
        HV * options = newHV();

    CODE:
        STRLEN keyStringLength;
        char* keyString;
        BIO *bio;
        SV * key = newSV(0);
        SV **svp;   // Temporary storage of options
        SV *digest = NULL;
        SV *format = newSVpv("pem", 3);
        IV days = 365;

        if (items > 1) {
            if (ST(1) != NULL) {
                // TODO: ensure_string_sv
                private_key = ST(1);
                if (strlen(SvPV_nolen(private_key)) == 0) {
                    private_key = NULL;
                }
            }

            if (items > 2)
                options = ensure_hv(ST(2), "options");
        }

        // Get the number of days for specified - default 365
        if (hv_exists(options, "days", strlen("days"))) {
            svp = hv_fetch(options, "days", strlen("days"), 0);

SignCSR.xs  view on Meta::CPAN


        // Get the output format - default is pem format
        if (hv_exists(options, "format", strlen("format"))) {
            svp = hv_fetch(options, "format", strlen("format"), 0);
            if (SvPOKp(*svp)) {
                format = *svp;
            }
        }

        // Get the private key and save it in memory
        keyString = SvPV(private_key, keyStringLength);
        bio = BIO_new_mem_buf(keyString, keyStringLength);
        if (bio == NULL) {
            croak ("Bio is null **** \n");
        }

        // Create the PrivateKey as EVP_PKEY
        EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, 0, NULL);
        if (pkey == NULL) {
            croak("Failed operation error code %d\n", errno);
        }

SignCSR.xs  view on Meta::CPAN

    HV * self;
    SV * request_SV;

    PREINIT:
        EVP_MD_CTX *mctx;

    CODE:

        SV **svp;
        MAGIC* mg;
        EVP_PKEY *private_key;
        X509_REQ * csr;
        int rv = 0;
        STRLEN request_length;
        unsigned char* request;
        BIO *csrbio;
        const char * digestname;
        STRLEN digestname_length;
        IV days;
        SV * digest = NULL;
        SV * format = NULL;

SignCSR.xs  view on Meta::CPAN

        //printf("Digest: %s\n", (char *) SvPV_nolen(digest));

        if (!hv_exists(self, "format", strlen("format")))
            croak("format not found in self!\n");

        svp = hv_fetch(self, "format", strlen("format"), 0);
        if (SvROK(*svp)) {
            format = SvRV(*svp);
        }

        private_key = (EVP_PKEY *) mg->mg_ptr;

        // Get the request that was passed into the sign function
        request = (unsigned char*) SvPV(request_SV, request_length);

        // Create the X509_REQ from the request
        csrbio = BIO_new_mem_buf(request, request_length);
        if (csrbio == NULL) {
            croak ("Bio for CRS Request is null **** \n");
        }
        csr = PEM_read_bio_X509_REQ(csrbio, NULL, NULL, NULL);

SignCSR.xs  view on Meta::CPAN

        // FIXME need to look at this
        //for (int i = X509_get_ext_count(x) - 1; i >= 0; i--) {
        //    X509_EXTENSION *ex = X509_get_ext(x, i);
        //    const char *sn = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ex)));

        //    if (clrext || (ext_names != NULL && strstr(ext_names, sn) == NULL))
        //        X509_EXTENSION_free(X509_delete_ext(x, i));
        //}

        // FIXME - this may need to change to support signing by different certificates
        if (private_key != NULL && !cert_matches_key(x, private_key))
            croak("cert_matches_key: signature key and public key of cert do not match\n");

        // Generate a serial number and update the certificate
        ASN1_INTEGER *sno = ASN1_INTEGER_new();
        if (sno == NULL || !rand_serial(NULL, sno))
            croak ("Unable to get ASN1INTEGER or random_serial\n");

        if (sno != NULL && !X509_set_serialNumber(x, sno))
            croak("X509_set_serialNumber cannot set serial number\n");

SignCSR.xs  view on Meta::CPAN

        X509 * issuer_cert = x;
        if (!X509_set_issuer_name(x, X509_get_subject_name(issuer_cert)))
            croak("X509_set_issuer_name cannot set issuer name\n");

        // Create the X509 v3 extensions for the certificate
        X509V3_CTX ext_ctx;

        // Set the certificate issuer from the private key
#if OPENSSL_API_COMPAT >= 30000
        X509V3_set_ctx(&ext_ctx, issuer_cert, x, NULL, NULL, X509V3_CTX_REPLACE);
        if (!X509V3_set_issuer_pkey(&ext_ctx, private_key))
            croak("X509V3_set_issuer_pkey cannot set issuer private key\n");
#elseif OPENSSL_API_COMPAT >=10010
        X509V3_set_ctx(&ext_ctx, issuer_cert, x, csr, NULL, X509V3_CTX_REPLACE);
#else
        X509V3_set_ctx(&ext_ctx, issuer_cert, x, csr, NULL, 0);
#endif

        // Set the X509 version of the certificate
#if OPENSSL_API_COMPAT >= 30000
        if (!X509_set_version(x, X509_VERSION_3))

SignCSR.xs  view on Meta::CPAN

        //printf ("DIGEST NAME = %s\n", digestname);
        // Allocate and a new digest context for certificate signing
#if OPENSSL_API_COMPAT <= 10100
        mctx = EVP_MD_CTX_create();
#else
        mctx = EVP_MD_CTX_new();
#endif

        // Sign the new certificate
#if OPENSSL_API_COMPAT >= 30101
        if (mctx != NULL && do_sign_init(mctx, private_key, digestname, NULL) > 0)
#else
        if (mctx != NULL && do_sign_init(mctx, private_key, md, NULL) > 0)
#endif
            rv = (X509_sign_ctx(x, mctx) > 0);

        if (rv == 0)
            croak("X509_sign_ctx cannot sign the new certificate\n");

        // Prepare to output new certificate
        BIO * out = BIO_new(BIO_s_mem());

        int i;

lib/Crypt/OpenSSL/SignCSR.pm  view on Meta::CPAN


=head1 NAME

Crypt::OpenSSL::SignCSR - Sign a Certificate Signing Request in XS.

=head1 SYNOPSIS

  use Crypt::OpenSSL::SignCSR;

  my $signer = Crypt::OpenSSL::SignCSR->new(
                                $private_key_pem
                                {   # OPTIONAL
                                    days    => $days,   # Number of days for the certificate
                                    digest  => $digest, # Signature digest default (SHA256)
                                    format  => $format, # Output format "text" or "pem" (default)
                                });
  my $cert   = $signer->sign(
                                $request, # CSR in PEM format
                            );

  my $ret = $signer->set_days(3650);

t/003-openssl-crypt-pkcs10.t  view on Meta::CPAN

l7ZyjUm0xGFuBG74iaw5ayUGdeNYDKk3sY5jK+PSaRhHcsA5Uoh+MAzhAoGAeiCM
tqBRmzDdRU/SNJs86U0fo0MiRpR5jO3NhH2n5t4fDgx/14n7+jvcnPRUXZ8gLkip
wVSBbxBTXE31rSPXHXrqk7SzwNuyax12Zop0bp+h3pirsZMgOfC1TQ4N1mBgzDRJ
8vvpCbwf9gSrReOPYTstyYIvqN8BY3nkWsSXElECgYA8MHCbPiE5v1SyE6B8yKO5
1/9Yg1unrwPBj6Q7YOUZLGaaWVuJfIvjkM/dOOypi170tMYWiOKk6RNz+j841thh
N3nGJfwRq+92jboNoqrhMxmMXFkPRIfpTBCIno6+i3ashVPND1fRrp/DWzA9hWGN
1ib27M8VSoEbTa+n4bmf3Q==
-----END PRIVATE KEY-----
PRIVKEY

my $priv = Crypt::OpenSSL::RSA->new_private_key($privkey);


my $req = Crypt::OpenSSL::PKCS10->new_from_rsa($priv);
isa_ok($req, "Crypt::OpenSSL::PKCS10");

$req->set_subject("/C=CA/ST=New Brunswick/O=XML::Sig/OU=perl");
$req->add_ext(Crypt::OpenSSL::PKCS10::NID_key_usage,"critical,digitalSignature,keyEncipherment");
$req->add_ext(Crypt::OpenSSL::PKCS10::NID_ext_key_usage,"serverAuth, nsSGC, msSGC, 1.3.4");
$req->add_ext(Crypt::OpenSSL::PKCS10::NID_subject_alt_name,"email:timlegge\@cpan.org");
#$req->add_custom_ext('1.2.3.3',"My new extension");



( run in 0.233 second using v1.01-cache-2.11-cpan-a5abf4f5562 )