Crypt-OpenSSL-SignCSR
view release on metacpan or search on metacpan
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);
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)
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);
// 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);
}
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;
//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);
// 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");
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))
//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 )