Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
5881 lines (4949 sloc) 140 KB
/* SSLeay.xs - Perl module for using Eric Young's implementation of SSL
*
* Copyright (c) 1996-2002 Sampo Kellomaki <sampo@iki.fi>
* Copyright (C) 2005 Florian Ragwitz <rafl@debian.org>
* Copyright (C) 2005 Mike McCauley <mikem@airspayce.com>
*
* All Rights Reserved.
*
* Change data removed. See Changes
*
* $Id: SSLeay.xs 426 2014-08-21 01:08:36Z mikem-guest $
*
* The distribution and use of this module are subject to the conditions
* listed in LICENSE file at the root of the Net-SSLeay
* distribution (i.e. same license as Perl itself).
*/
/* ####
* #### PLEASE READ THE FOLLOWING RULES BEFORE YOU START EDITING THIS FILE! ####
* ####
*
* Function naming conventions:
*
* 1/ never change the already existing function names (all calling convention) in a way
* that may cause backward incompatibility (e.g. add ALIAS with old name if necessary)
*
* 2/ it is recommended to keep the original openssl function names for functions that are:
*
* 1:1 wrappers to the original openssl functions
* see for example: X509_get_issuer_name(cert) >> Net::SSLeay::X509_get_issuer_name($cert)
*
* nearly 1:1 wrappers implementing only necessary "glue" e.g. buffer handling
* see for example: RAND_seed(buf,len) >> Net::SSLeay::RAND_seed($buf)
*
* 3/ OpenSSL functions starting with "SSL_" are added into SSLeay.xs with "SLL_" prefix
* (e.g. SSL_CTX_new) but keep in mind that they will be available in Net::SSLeay without
* "SSL_" prefix (e.g. Net::SSLeay::CTX_new) - keep this for all new functions
*
* 4/ The names of functions which do not fit rule 2/ (which means they implement some non
* trivial code around original openssl function or do more complex tasks) should be
* prefixed with "P_" - see for example: P_ASN1_TIME_set_isotime
*
* 5/ Exceptions from rules above:
* functions that are part or wider set of already existing function not following this rule
* for example: there already exists: PEM_get_string_X509_CRL + PEM_get_string_X509_REQ and you want
* to add PEM_get_string_SOMETHING - then no need to follow 3/ (do not prefix with "P_")
*
* Support for different openssl versions, different platforms, different compilers:
*
* 1/ SSleay.xs is expected to build/pass test suite
* - with openssl 0.9.6 and newer versions
* - with perl 5.8 and newer versions
*
* 2/ Fix all compiler warnings - we expect 100% clean build
*
* 3/ If you add a function which is available since certain openssl version
* use proper #ifdefs to assure that SSLeay.xs will compile also with older versions
* which are missing this function
*
* 4/ Even warnings arising from different use of "const" in different openssl versions
* needs to be hanled with #ifdefs - see for example: X509_NAME_add_entry_by_txt
*
* 5/ avoid using global C variables (it is very likely to break thread-safetyness)
* use rather global MY_CXT structure
*
* 6/ avoid using any UNIX/POSIX specific functions, keep in mind that SSLeay.xs must
* compile also on non-UNIX platforms like MS Windows and others
*
* 7/ avoid using c++ comments "//" (or other c++ features accepted by some c compiler)
* even if your compiler can handle them without warnings
*
* Passing test suite:
*
* 1/ any changes to SSLeay.xs must not introduce a failure of existing test suite
*
* 2/ it is strongly recommended to create test(s) for newly added function(s), especially
* when the new function is not only a 1:1 wrapper but contains a complex code
*
* 3/ it is mandatory to add a documentation for all newly added functions into SSLeay.pod
* otherwise t/local/02_pod_coverage.t fail (and you will be asked to add some doc into
* your patch)
*
* Preferred code layout:
*
* 1/ for simple 1:1 XS wrappers use:
*
* a/ functions with short "signature" (short list of args):
*
* long
* SSL_set_tmp_dh(SSL *ssl,DH *dh)
*
* b/ functions with long "signature" (long list of args):
* simply when approach a/ does not fit to 120 columns
*
* void
* SSL_any_functions(library_flag,function_name,reason,file_name,line)
* int library_flag
* int function_name
* int reason
* char *file_name
* int line
*
* 2/ for XS functions with full implementation use identation like this:
*
* int
* RAND_bytes(buf, num)
* SV *buf
* int num
* PREINIT:
* int rc;
* unsigned char *random;
* CODE:
* / * some code here * /
* RETVAL = rc;
* OUTPUT:
* RETVAL
*
*
* Runtime debugging:
*
* with TRACE(level,fmt,...) you can output debug messages.
* it behaves the same as
* warn sprintf($msg,...) if $Net::SSLeay::trace>=$level
* would do in Perl (e.g. it is using also the $Net::SSLeay::trace variable)
*
*
* THE LAST RULE:
*
* The fact that some parts of SSLeay.xs do not follow the rules above is not
* a reason why any new code can also break these rules in the same way
*
*/
/* Prevent warnings about strncpy from Windows compilers */
#define _CRT_SECURE_NO_DEPRECATE
#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <stdarg.h>
#define NEED_newRV_noinc
#define NEED_sv_2pv_flags
#define NEED_my_snprintf
#include "ppport.h"
#ifdef __cplusplus
}
#endif
/* OpenSSL-0.9.3a has some strange warning about this in
* openssl/des.h
*/
#undef _
/* Sigh: openssl 1.0 has
typedef void *BLOCK;
which conflicts with perls
typedef struct block BLOCK;
*/
#define BLOCK OPENSSL_BLOCK
#include <openssl/err.h>
#include <openssl/lhash.h>
#include <openssl/rand.h>
#include <openssl/buffer.h>
#include <openssl/ssl.h>
#include <openssl/pkcs12.h>
#include <openssl/comp.h> /* openssl-0.9.6a forgets to include this */
#ifndef OPENSSL_NO_MD2
#include <openssl/md2.h>
#endif
#include <openssl/md4.h>
#include <openssl/md5.h> /* openssl-SNAP-20020227 does not automatically include this */
#if OPENSSL_VERSION_NUMBER >= 0x00905000L
#include <openssl/ripemd.h>
#endif
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#if OPENSSL_VERSION_NUMBER >= 0x0090700fL
/* requires 0.9.7+ */
#include <openssl/engine.h>
#endif
#ifdef OPENSSL_FIPS
#include <openssl/fips.h>
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
#include <openssl/ocsp.h>
#endif
#undef BLOCK
/* Debugging output - to enable use:
*
* perl Makefile.PL DEFINE=-DSHOW_XS_DEBUG
* make
*
*/
#ifdef SHOW_XS_DEBUG
#define PR1(s) fprintf(stderr,s);
#define PR2(s,t) fprintf(stderr,s,t);
#define PR3(s,t,u) fprintf(stderr,s,t,u);
#define PR4(s,t,u,v) fprintf(stderr,s,t,u,v);
#else
#define PR1(s)
#define PR2(s,t)
#define PR3(s,t,u)
#define PR4(s,t,u,v)
#endif
static void TRACE(int level,char *msg,...) {
va_list args;
SV *trace = get_sv("Net::SSLeay::trace",0);
if (trace && SvIOK(trace) && SvIV(trace)>=level) {
char buf[4096];
va_start(args,msg);
vsnprintf(buf,4095,msg,args);
warn("%s",buf);
}
}
#include "constants.c"
/* ============= thread-safety related stuff ============== */
#define MY_CXT_KEY "Net::SSLeay::_guts" XS_VERSION
typedef struct {
HV* global_cb_data;
UV tid;
} my_cxt_t;
START_MY_CXT
#ifdef USE_ITHREADS
static perl_mutex LIB_init_mutex;
static perl_mutex *GLOBAL_openssl_mutex = NULL;
#endif
static int LIB_initialized;
UV get_my_thread_id(void) /* returns threads->tid() value */
{
dSP;
UV tid = 0;
int count = 0;
#ifdef USE_ITHREADS
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSVpv("threads", 0)));
PUTBACK;
count = call_method("tid", G_SCALAR|G_EVAL);
SPAGAIN;
if (SvTRUE(ERRSV) || count != 1)
/* if threads not loaded or an error occurs return 0 */
tid = 0;
else
tid = (UV)POPi;
PUTBACK;
FREETMPS;
LEAVE;
#endif
return tid;
}
/* IMPORTANT NOTE:
* openssl locking was implemented according to http://www.openssl.org/docs/crypto/threads.html
* we implement both static and dynamic locking as described on URL above
* locking is supported when OPENSSL_THREADS macro is defined which means openssl-0.9.7 or newer
* we intentionally do not implement cleanup of openssl's threading as it causes troubles
* with apache-mpm-worker+mod_perl+mod_ssl+net-ssleay
*/
#if defined(USE_ITHREADS) && defined(OPENSSL_THREADS)
static void openssl_locking_function(int mode, int type, const char *file, int line)
{
PR3("openssl_locking_function %d %d\n", mode, type);
if (!GLOBAL_openssl_mutex) return;
if (mode & CRYPTO_LOCK)
MUTEX_LOCK(&GLOBAL_openssl_mutex[type]);
else
MUTEX_UNLOCK(&GLOBAL_openssl_mutex[type]);
}
#if OPENSSL_VERSION_NUMBER < 0x10000000L
static unsigned long openssl_threadid_func(void)
{
dMY_CXT;
return (unsigned long)(MY_CXT.tid);
}
#else
void openssl_threadid_func(CRYPTO_THREADID *id)
{
dMY_CXT;
CRYPTO_THREADID_set_numeric(id, (unsigned long)(MY_CXT.tid));
}
#endif
struct CRYPTO_dynlock_value
{
perl_mutex mutex;
};
struct CRYPTO_dynlock_value * openssl_dynlocking_create_function (const char *file, int line)
{
struct CRYPTO_dynlock_value *retval;
New(0, retval, 1, struct CRYPTO_dynlock_value);
if (!retval) return NULL;
MUTEX_INIT(&retval->mutex);
return retval;
}
void openssl_dynlocking_lock_function (int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)
{
if (!l) return;
if (mode & CRYPTO_LOCK)
MUTEX_LOCK(&l->mutex);
else
MUTEX_UNLOCK(&l->mutex);
}
void openssl_dynlocking_destroy_function (struct CRYPTO_dynlock_value *l, const char *file, int line)
{
if (!l) return;
MUTEX_DESTROY(&l->mutex);
Safefree(l);
}
void openssl_threads_init(void)
{
int i;
PR1("STARTED: openssl_threads_init\n");
/* initialize static locking */
if ( !CRYPTO_get_locking_callback() ) {
#if OPENSSL_VERSION_NUMBER < 0x10000000L
if ( !CRYPTO_get_id_callback() ) {
#else
if ( !CRYPTO_THREADID_get_callback() ) {
#endif
PR2("openssl_threads_init static locking %d\n", CRYPTO_num_locks());
New(0, GLOBAL_openssl_mutex, CRYPTO_num_locks(), perl_mutex);
if (!GLOBAL_openssl_mutex) return;
for (i=0; i<CRYPTO_num_locks(); i++) MUTEX_INIT(&GLOBAL_openssl_mutex[i]);
CRYPTO_set_locking_callback((void (*)(int,int,const char *,int))openssl_locking_function);
#ifndef WIN32
/* no need for threadid_func() on Win32 */
#if OPENSSL_VERSION_NUMBER < 0x10000000L
CRYPTO_set_id_callback(openssl_threadid_func);
#else
CRYPTO_THREADID_set_callback(openssl_threadid_func);
#endif
#endif
}
}
/* initialize dynamic locking */
if ( !CRYPTO_get_dynlock_create_callback() &&
!CRYPTO_get_dynlock_lock_callback() &&
!CRYPTO_get_dynlock_destroy_callback() ) {
PR1("openssl_threads_init dynamic locking\n");
CRYPTO_set_dynlock_create_callback(openssl_dynlocking_create_function);
CRYPTO_set_dynlock_lock_callback(openssl_dynlocking_lock_function);
CRYPTO_set_dynlock_destroy_callback(openssl_dynlocking_destroy_function);
}
}
#endif
/* ============= typedefs to agument TYPEMAP ============== */
typedef void callback_no_ret(void);
typedef RSA * cb_ssl_int_int_ret_RSA(SSL * ssl,int is_export, int keylength);
typedef DH * cb_ssl_int_int_ret_DH(SSL * ssl,int is_export, int keylength);
typedef STACK_OF(X509_NAME) X509_NAME_STACK;
typedef int perl_filehandle_t;
/* ======= special handler used by EVP_MD_do_all_sorted ======= */
#if OPENSSL_VERSION_NUMBER >= 0x1000000fL
static void handler_list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg)
{
/* taken from apps/dgst.c */
const char *mname;
if (!m) return; /* Skip aliases */
mname = OBJ_nid2ln(EVP_MD_type(m));
if (strcmp(from, mname)) return; /* Skip shortnames */
if (EVP_MD_flags(m) & EVP_MD_FLAG_PKEY_DIGEST) return; /* Skip clones */
if (strchr(mname, ' ')) mname= EVP_MD_name(m);
av_push(arg, newSVpv(mname,0));
}
#endif
/* ============= callbacks - basic info =============
*
* PLEASE READ THIS BEFORE YOU ADD ANY NEW CALLBACK!!
*
* There are basically 2 types of callbacks used in SSLeay:
*
* 1/ "one-time" callbacks - these are created+used+destroyed within one perl function implemented in XS
* these callbacks use a cpecial C structupe simple_cb_data_t to pass necessary data
* there are 2 related helper functions: simple_cb_data_new() + simple_cb_data_free
* for example see implementation of these functions:
* - RSA_generate_key
* - PEM_read_bio_PrivateKey
*
* 2/ "advanced" callbacks - these are setup/destroyed by one function but used by another function; these
* callbacks use global hash MY_CXT.global_cb_data to store perl functions + data to be uset at callback time
* there are 2 related helper functions: cb_data_advanced_put() + cb_data_advanced_get for manipulating
* global hash MY_CXT.global_cb_data which work like this:
* cb_data_advanced_put(<pointer>, "data_name", dataSV)
* >>>
* global_cb_data->{"ptr_<pointer>"}->{"data_name"} = dataSV)
* or
* data = cb_data_advanced_get(<pointer>, "data_name")
* >>>
* my $data = global_cb_data->{"ptr_<pointer>"}->{"data_name"}
* for example see implementation of these functions:
* - SSL_CTX_set_verify
* - SSL_set_verify
* - SSL_CTX_set_cert_verify_callback
* - SSL_CTX_set_default_passwd_cb
* - SSL_CTX_set_default_passwd_cb_userdata
* - SSL_set_session_secret_cb
*
* If you want to add a new callback:
* - you very likely need a new function "your_callback_name_invoke()"
* - decide whether your case fits case 1/ or 2/ (and implement likewise existing functions)
* - try to avoid adding a new style of callback implementation (or ask Net::SSLeay maintainers before)
*
*/
/* ============= callback stuff - generic functions============== */
struct _ssleay_cb_t {
SV* func;
SV* data;
};
typedef struct _ssleay_cb_t simple_cb_data_t;
simple_cb_data_t* simple_cb_data_new(SV* func, SV* data)
{
simple_cb_data_t* cb;
New(0, cb, 1, simple_cb_data_t);
if (cb) {
SvREFCNT_inc(func);
SvREFCNT_inc(data);
cb->func = func;
cb->data = (data == &PL_sv_undef) ? NULL : data;
}
return cb;
}
void simple_cb_data_free(simple_cb_data_t* cb)
{
if (cb) {
if (cb->func) {
SvREFCNT_dec(cb->func);
cb->func = NULL;
}
if (cb->data) {
SvREFCNT_dec(cb->data);
cb->data = NULL;
}
}
Safefree(cb);
}
int cb_data_advanced_put(void *ptr, const char* data_name, SV* data)
{
HV * L2HV;
SV ** svtmp;
int len;
char key_name[500];
dMY_CXT;
len = my_snprintf(key_name, sizeof(key_name), "ptr_%p", ptr);
if (len == sizeof(key_name)) return 0; /* error - key_name too short*/
/* get or create level-2 hash */
svtmp = hv_fetch(MY_CXT.global_cb_data, key_name, strlen(key_name), 0);
if (svtmp == NULL) {
L2HV = newHV();
hv_store(MY_CXT.global_cb_data, key_name, strlen(key_name), newRV_noinc((SV*)L2HV), 0);
}
else {
if (!SvOK(*svtmp) || !SvROK(*svtmp)) return 0;
#if defined(MUTABLE_PTR)
L2HV = (HV*)MUTABLE_PTR(SvRV(*svtmp));
#else
L2HV = (HV*)(SvRV(*svtmp));
#endif
}
/* first delete already stored value */
hv_delete(L2HV, data_name, strlen(data_name), G_DISCARD);
if (data!=NULL)
if (SvOK(data))
hv_store(L2HV, data_name, strlen(data_name), data, 0);
return 1;
}
SV* cb_data_advanced_get(void *ptr, const char* data_name)
{
HV * L2HV;
SV ** svtmp;
int len;
char key_name[500];
dMY_CXT;
len = my_snprintf(key_name, sizeof(key_name), "ptr_%p", ptr);
if (len == sizeof(key_name)) return &PL_sv_undef; /* return undef on error - key_name too short*/
/* get level-2 hash */
svtmp = hv_fetch(MY_CXT.global_cb_data, key_name, strlen(key_name), 0);
if (svtmp == NULL) return &PL_sv_undef;
if (!SvOK(*svtmp)) return &PL_sv_undef;
if (!SvROK(*svtmp)) return &PL_sv_undef;
#if defined(MUTABLE_PTR)
L2HV = (HV*)MUTABLE_PTR(SvRV(*svtmp));
#else
L2HV = (HV*)(SvRV(*svtmp));
#endif
/* get stored data */
svtmp = hv_fetch(L2HV, data_name, strlen(data_name), 0);
if (svtmp == NULL) return &PL_sv_undef;
if (!SvOK(*svtmp)) return &PL_sv_undef;
return *svtmp;
}
int cb_data_advanced_drop(void *ptr)
{
int len;
char key_name[500];
dMY_CXT;
len = my_snprintf(key_name, sizeof(key_name), "ptr_%p", ptr);
if (len == sizeof(key_name)) return 0; /* error - key_name too short*/
hv_delete(MY_CXT.global_cb_data, key_name, strlen(key_name), G_DISCARD);
return 1;
}
/* ============= callback stuff - invoke functions ============== */
static int ssleay_verify_callback_invoke (int ok, X509_STORE_CTX* x509_store)
{
dSP;
SSL* ssl;
int count = -1, res;
SV *cb_func;
PR1("STARTED: ssleay_verify_callback_invoke\n");
ssl = X509_STORE_CTX_get_ex_data(x509_store, SSL_get_ex_data_X509_STORE_CTX_idx());
cb_func = cb_data_advanced_get(ssl, "ssleay_verify_callback!!func");
if (!SvOK(cb_func)) {
SSL_CTX* ssl_ctx = SSL_get_SSL_CTX(ssl);
cb_func = cb_data_advanced_get(ssl_ctx, "ssleay_verify_callback!!func");
}
if (!SvOK(cb_func))
croak("Net::SSLeay: verify_callback called, but not set to point to any perl function.\n");
ENTER;
SAVETMPS;
PR2("verify callback glue ok=%d\n", ok);
PUSHMARK(sp);
EXTEND( sp, 2 );
PUSHs( sv_2mortal(newSViv(ok)) );
PUSHs( sv_2mortal(newSViv(PTR2IV(x509_store))) );
PUTBACK;
PR1("About to call verify callback.\n");
count = call_sv(cb_func, G_SCALAR);
PR1("Returned from verify callback.\n");
SPAGAIN;
if (count != 1)
croak ( "Net::SSLeay: verify_callback perl function did not return a scalar.\n");
res = POPi;
PUTBACK;
FREETMPS;
LEAVE;
return res;
}
static int ssleay_ctx_passwd_cb_invoke(char *buf, int size, int rwflag, void *userdata)
{
dSP;
int count = -1;
char *res;
SV *cb_func, *cb_data;
PR1("STARTED: ssleay_ctx_passwd_cb_invoke\n");
cb_func = cb_data_advanced_get(userdata, "ssleay_ctx_passwd_cb!!func");
cb_data = cb_data_advanced_get(userdata, "ssleay_ctx_passwd_cb!!data");
if(!SvOK(cb_func))
croak ("Net::SSLeay: ssleay_ctx_passwd_cb_invoke called, but not set to point to any perl function.\n");
ENTER;
SAVETMPS;
PUSHMARK(sp);
XPUSHs(sv_2mortal(newSViv(rwflag)));
XPUSHs(sv_2mortal(newSVsv(cb_data)));
PUTBACK;
count = call_sv( cb_func, G_SCALAR );
SPAGAIN;
if (count != 1)
croak("Net::SSLeay: ssleay_ctx_passwd_cb_invoke perl function did not return a scalar.\n");
res = POPp;
if (res == NULL) {
*buf = '\0';
} else {
strncpy(buf, res, size);
buf[size - 1] = '\0';
}
PUTBACK;
FREETMPS;
LEAVE;
return strlen(buf);
}
int ssleay_ctx_cert_verify_cb_invoke(X509_STORE_CTX* x509_store_ctx, void* data)
{
dSP;
int count = -1;
int res;
SV * cb_func, *cb_data;
void *ptr;
SSL *ssl;
PR1("STARTED: ssleay_ctx_cert_verify_cb_invoke\n");
#if OPENSSL_VERSION_NUMBER < 0x0090700fL
ssl = X509_STORE_CTX_get_ex_data(x509_store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
ptr = (void*) SSL_get_SSL_CTX(ssl);
#else
ssl = NULL;
ptr = (void*) data;
#endif
cb_func = cb_data_advanced_get(ptr, "ssleay_ctx_cert_verify_cb!!func");
cb_data = cb_data_advanced_get(ptr, "ssleay_ctx_cert_verify_cb!!data");
if(!SvOK(cb_func))
croak ("Net::SSLeay: ssleay_ctx_cert_verify_cb_invoke called, but not set to point to any perl function.\n");
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(PTR2IV(x509_store_ctx))));
XPUSHs(sv_2mortal(newSVsv(cb_data)));
PUTBACK;
count = call_sv(cb_func, G_SCALAR);
SPAGAIN;
if (count != 1)
croak("Net::SSLeay: ssleay_ctx_cert_verify_cb_invoke perl function did not return a scalar.\n");
res = POPi;
PUTBACK;
FREETMPS;
LEAVE;
return res;
}
#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
int tlsext_servername_callback_invoke(SSL *ssl, int *ad, void *arg)
{
dSP;
int count = -1;
int res;
SV * cb_func, *cb_data;
PR1("STARTED: tlsext_servername_callback_invoke\n");
cb_func = cb_data_advanced_get(arg, "tlsext_servername_callback!!func");
cb_data = cb_data_advanced_get(arg, "tlsext_servername_callback!!data");
if(!SvOK(cb_func))
croak ("Net::SSLeay: tlsext_servername_callback_invoke called, but not set to point to any perl function.\n");
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(PTR2IV(ssl))));
XPUSHs(sv_2mortal(newSVsv(cb_data)));
PUTBACK;
count = call_sv(cb_func, G_SCALAR);
SPAGAIN;
if (count != 1)
croak("Net::SSLeay: tlsext_servername_callback_invoke perl function did not return a scalar.\n");
res = POPi;
PUTBACK;
FREETMPS;
LEAVE;
return res;
}
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_TLSEXT)
int tlsext_status_cb_invoke(SSL *ssl, void *arg)
{
dSP;
SV *cb_func, *cb_data;
SSL_CTX *ctx = SSL_get_SSL_CTX(ssl);
int len,res,nres = -1;
const unsigned char *p = NULL;
OCSP_RESPONSE *ocsp_response = NULL;
cb_func = cb_data_advanced_get(ctx, "tlsext_status_cb!!func");
cb_data = cb_data_advanced_get(ctx, "tlsext_status_cb!!data");
if ( ! SvROK(cb_func) || (SvTYPE(SvRV(cb_func)) != SVt_PVCV))
croak ("Net::SSLeay: tlsext_status_cb_invoke called, but not set to point to any perl function.\n");
len = SSL_get_tlsext_status_ocsp_resp(ssl, &p);
if (p) ocsp_response = d2i_OCSP_RESPONSE(NULL, &p, len);
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(PTR2IV(ssl))));
PUSHs( sv_2mortal(newSViv(PTR2IV(ocsp_response))) );
XPUSHs(sv_2mortal(newSVsv(cb_data)));
PUTBACK;
nres = call_sv(cb_func, G_SCALAR);
OCSP_RESPONSE_free(ocsp_response);
SPAGAIN;
if (nres != 1)
croak("Net::SSLeay: tlsext_status_cb_invoke perl function did not return a scalar.\n");
res = POPi;
PUTBACK;
FREETMPS;
LEAVE;
return res;
}
#endif
#if defined(SSL_F_SSL_SET_HELLO_EXTENSION) || defined(SSL_F_SSL_SET_SESSION_TICKET_EXT)
int ssleay_session_secret_cb_invoke(SSL* s, void* secret, int *secret_len,
STACK_OF(SSL_CIPHER) *peer_ciphers,
SSL_CIPHER **cipher, void *arg)
{
dSP;
int count = -1, res, i;
AV *ciphers = newAV();
SV *pref_cipher = sv_newmortal();
SV * cb_func, *cb_data;
PR1("STARTED: ssleay_session_secret_cb_invoke\n");
cb_func = cb_data_advanced_get(arg, "ssleay_session_secret_cb!!func");
cb_data = cb_data_advanced_get(arg, "ssleay_session_secret_cb!!data");
if(!SvOK(cb_func))
croak ("Net::SSLeay: ssleay_ctx_passwd_cb_invoke called, but not set to point to any perl function.\n");
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs( sv_2mortal( newSVpv(secret, *secret_len)) );
for (i=0; i<sk_SSL_CIPHER_num(peer_ciphers); i++) {
SSL_CIPHER *c = sk_SSL_CIPHER_value(peer_ciphers,i);
av_store(ciphers, i, sv_2mortal(newSVpv(SSL_CIPHER_get_name(c), 0)));
}
XPUSHs(sv_2mortal(newRV_inc((SV*)ciphers)));
XPUSHs(sv_2mortal(newRV_inc(pref_cipher)));
XPUSHs(sv_2mortal(newSVsv(cb_data)));
PUTBACK;
count = call_sv( cb_func, G_SCALAR );
SPAGAIN;
if (count != 1)
croak ("Net::SSLeay: ssleay_session_secret_cb_invoke perl function did not return a scalar.\n");
res = POPi;
if (res) {
/* See if there is a preferred cipher selected, if so it is an index into the stack */
if (SvIOK(pref_cipher))
*cipher = sk_SSL_CIPHER_value(peer_ciphers, SvIV(pref_cipher));
}
PUTBACK;
FREETMPS;
LEAVE;
return res;
}
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_NEXTPROTONEG)
int next_proto_helper_AV2protodata(AV * list, unsigned char *out)
{
int i, last_index, ptr = 0;
last_index = av_len(list);
if (last_index<0) return 0;
for(i=0; i<=last_index; i++) {
char *p = SvPV_nolen(*av_fetch(list, i, 0));
size_t len = strlen(p);
if (len>255) return 0;
if (out) {
/* if out == NULL we only calculate the length of output */
out[ptr] = (unsigned char)len;
strncpy((char*)out+ptr+1, p, len);
}
ptr += strlen(p) + 1;
}
return ptr;
}
int next_proto_helper_protodata2AV(AV * list, const unsigned char *in, unsigned int inlen)
{
unsigned int i = 0;
unsigned char il;
if (!list || inlen<2) return 0;
while (i<inlen) {
il = in[i++];
if (i+il > inlen) return 0;
av_push(list, newSVpv((const char*)in+i, il));
i += il;
}
return 1;
}
int next_proto_select_cb_invoke(SSL *ssl, unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen, void *arg)
{
SV *cb_func, *cb_data;
unsigned char *next_proto_data;
size_t next_proto_len;
int next_proto_status;
SSL_CTX *ctx = SSL_get_SSL_CTX(ssl);
/* this n_a is required for building with old perls: */
STRLEN n_a;
PR1("STARTED: next_proto_select_cb_invoke\n");
cb_func = cb_data_advanced_get(ctx, "next_proto_select_cb!!func");
cb_data = cb_data_advanced_get(ctx, "next_proto_select_cb!!data");
/* clear last_status value = store undef */
cb_data_advanced_put(ssl, "next_proto_select_cb!!last_status", NULL);
cb_data_advanced_put(ssl, "next_proto_select_cb!!last_negotiated", NULL);
if (SvROK(cb_func) && (SvTYPE(SvRV(cb_func)) == SVt_PVCV)) {
int count = -1;
AV *list = newAV();
SV *tmpsv;
dSP;
if (!next_proto_helper_protodata2AV(list, in, inlen)) return SSL_TLSEXT_ERR_ALERT_FATAL;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(PTR2IV(ssl))));
XPUSHs(sv_2mortal(newRV_inc((SV*)list)));
XPUSHs(sv_2mortal(newSVsv(cb_data)));
PUTBACK;
count = call_sv( cb_func, G_ARRAY );
SPAGAIN;
if (count != 2)
croak ("Net::SSLeay: next_proto_select_cb_invoke perl function did not return 2 values.\n");
next_proto_data = (unsigned char*)POPpx;
next_proto_status = POPi;
next_proto_len = strlen((const char*)next_proto_data);
if (next_proto_len<=255) {
/* store last_status + last_negotiated into global hash */
cb_data_advanced_put(ssl, "next_proto_select_cb!!last_status", newSViv(next_proto_status));
tmpsv = newSVpv((const char*)next_proto_data, next_proto_len);
cb_data_advanced_put(ssl, "next_proto_select_cb!!last_negotiated", tmpsv);
*out = (unsigned char *)SvPVX(tmpsv);
*outlen = next_proto_len;
}
PUTBACK;
FREETMPS;
LEAVE;
return next_proto_len>255 ? SSL_TLSEXT_ERR_ALERT_FATAL : SSL_TLSEXT_ERR_OK;
}
else if (SvROK(cb_data) && (SvTYPE(SvRV(cb_data)) == SVt_PVAV)) {
next_proto_len = next_proto_helper_AV2protodata((AV*)SvRV(cb_data), NULL);
Newx(next_proto_data, next_proto_len, unsigned char);
if (!next_proto_data) return SSL_TLSEXT_ERR_ALERT_FATAL;
next_proto_len = next_proto_helper_AV2protodata((AV*)SvRV(cb_data), next_proto_data);
next_proto_status = SSL_select_next_proto(out, outlen, in, inlen, next_proto_data, next_proto_len);
/* store last_status + last_negotiated into global hash */
cb_data_advanced_put(ssl, "next_proto_select_cb!!last_status", newSViv(next_proto_status));
cb_data_advanced_put(ssl, "next_proto_select_cb!!last_negotiated", newSVpv((const char*)*out, *outlen));
Safefree(next_proto_data);
return SSL_TLSEXT_ERR_OK;
}
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
int next_protos_advertised_cb_invoke(SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg_unused)
{
SV *cb_func, *cb_data;
unsigned char *protodata = NULL;
unsigned short protodata_len = 0;
SV *tmpsv;
AV *tmpav;
SSL_CTX *ctx = SSL_get_SSL_CTX(ssl);
PR1("STARTED: next_protos_advertised_cb_invoke");
cb_func = cb_data_advanced_get(ctx, "next_protos_advertised_cb!!func");
cb_data = cb_data_advanced_get(ctx, "next_protos_advertised_cb!!data");
if (SvROK(cb_func) && (SvTYPE(SvRV(cb_func)) == SVt_PVCV)) {
int count = -1;
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(PTR2IV(ssl))));
XPUSHs(sv_2mortal(newSVsv(cb_data)));
PUTBACK;
count = call_sv( cb_func, G_SCALAR );
SPAGAIN;
if (count != 1)
croak ("Net::SSLeay: next_protos_advertised_cb_invoke perl function did not return scalar value.\n");
tmpsv = POPs;
if (SvOK(tmpsv) && SvROK(tmpsv) && (SvTYPE(SvRV(tmpsv)) == SVt_PVAV)) {
tmpav = (AV*)SvRV(tmpsv);
protodata_len = next_proto_helper_AV2protodata(tmpav, NULL);
Newx(protodata, protodata_len, unsigned char);
if (protodata) next_proto_helper_AV2protodata(tmpav, protodata);
}
PUTBACK;
FREETMPS;
LEAVE;
}
else if (SvROK(cb_data) && (SvTYPE(SvRV(cb_data)) == SVt_PVAV)) {
tmpav = (AV*)SvRV(cb_data);
protodata_len = next_proto_helper_AV2protodata(tmpav, NULL);
Newx(protodata, protodata_len, unsigned char);
if (protodata) next_proto_helper_AV2protodata(tmpav, protodata);
}
if (protodata) {
tmpsv = newSVpv((const char*)protodata, protodata_len);
Safefree(protodata);
cb_data_advanced_put(ssl, "next_protos_advertised_cb!!last_advertised", tmpsv);
*out = (unsigned char *)SvPVX(tmpsv);
*outlen = protodata_len;
return SSL_TLSEXT_ERR_OK;
}
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(OPENSSL_NO_TLSEXT)
int alpn_select_cb_invoke(SSL *ssl, const unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen, void *arg)
{
SV *cb_func, *cb_data;
unsigned char *alpn_data;
size_t alpn_len;
SSL_CTX *ctx = SSL_get_SSL_CTX(ssl);
PR1("STARTED: alpn_select_cb_invoke\n");
cb_func = cb_data_advanced_get(ctx, "alpn_select_cb!!func");
cb_data = cb_data_advanced_get(ctx, "alpn_select_cb!!data");
if (SvROK(cb_func) && (SvTYPE(SvRV(cb_func)) == SVt_PVCV)) {
int count = -1;
AV *list = newAV();
SV *tmpsv;
SV *alpn_data_sv;
dSP;
if (!next_proto_helper_protodata2AV(list, in, inlen)) return SSL_TLSEXT_ERR_ALERT_FATAL;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(PTR2IV(ssl))));
XPUSHs(sv_2mortal(newRV_inc((SV*)list)));
XPUSHs(sv_2mortal(newSVsv(cb_data)));
PUTBACK;
count = call_sv( cb_func, G_ARRAY );
SPAGAIN;
if (count != 1)
croak ("Net::SSLeay: alpn_select_cb perl function did not return exactly 1 value.\n");
alpn_data_sv = POPs;
if (SvOK(alpn_data_sv)) {
alpn_data = (unsigned char*)SvPVx_nolen(alpn_data_sv);
alpn_len = strlen((const char*)alpn_data);
if (alpn_len <= 255) {
tmpsv = newSVpv((const char*)alpn_data, alpn_len);
*out = (unsigned char *)SvPVX(tmpsv);
*outlen = alpn_len;
}
} else {
alpn_data = NULL;
alpn_len = 0;
}
PUTBACK;
FREETMPS;
LEAVE;
if (alpn_len>255) return SSL_TLSEXT_ERR_ALERT_FATAL;
return alpn_data ? SSL_TLSEXT_ERR_OK : SSL_TLSEXT_ERR_NOACK;
}
else if (SvROK(cb_data) && (SvTYPE(SvRV(cb_data)) == SVt_PVAV)) {
int status;
alpn_len = next_proto_helper_AV2protodata((AV*)SvRV(cb_data), NULL);
Newx(alpn_data, alpn_len, unsigned char);
if (!alpn_data) return SSL_TLSEXT_ERR_ALERT_FATAL;
alpn_len = next_proto_helper_AV2protodata((AV*)SvRV(cb_data), alpn_data);
/* This is the same function that is used for NPN. */
status = SSL_select_next_proto((unsigned char **)out, outlen, in, inlen, alpn_data, alpn_len);
Safefree(alpn_data);
return status == OPENSSL_NPN_NEGOTIATED ? SSL_TLSEXT_ERR_OK : SSL_TLSEXT_ERR_NOACK;
}
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
#endif
int pem_password_cb_invoke(char *buf, int bufsize, int rwflag, void *data) {
dSP;
char *str;
int count = -1;
size_t str_len = 0;
simple_cb_data_t* cb = (simple_cb_data_t*)data;
/* this n_a is required for building with old perls: */
STRLEN n_a;
PR1("STARTED: pem_password_cb_invoke\n");
if (cb->func && SvOK(cb->func)) {
ENTER;
SAVETMPS;
PUSHMARK(sp);
XPUSHs(sv_2mortal( newSViv(bufsize-1) ));
XPUSHs(sv_2mortal( newSViv(rwflag) ));
if (cb->data) XPUSHs( cb->data );
PUTBACK;
count = call_sv( cb->func, G_SCALAR );
SPAGAIN;
buf[0] = 0; /* start with an empty password */
if (count != 1) {
croak("Net::SSLeay: pem_password_cb_invoke perl function did not return a scalar.\n");
}
else {
str = POPpx;
str_len = strlen(str);
if (str_len+1 < bufsize) {
strcpy(buf, str);
}
else {
str_len = 0;
warn("Net::SSLeay: pem_password_cb_invoke password too long\n");
}
}
PUTBACK;
FREETMPS;
LEAVE;
}
return str_len;
}
void ssleay_RSA_generate_key_cb_invoke(int i, int n, void* data)
{
dSP;
int count = -1;
simple_cb_data_t* cb = (simple_cb_data_t*)data;
/* PR1("STARTED: ssleay_RSA_generate_key_cb_invoke\n"); / * too noisy */
if (cb->func && SvOK(cb->func)) {
ENTER;
SAVETMPS;
PUSHMARK(sp);
XPUSHs(sv_2mortal( newSViv(i) ));
XPUSHs(sv_2mortal( newSViv(n) ));
if (cb->data) XPUSHs( cb->data );
PUTBACK;
count = call_sv( cb->func, G_VOID|G_DISCARD );
if (count != 0)
croak ("Net::SSLeay: ssleay_RSA_generate_key_cb_invoke "
"perl function did return something in void context.\n");
SPAGAIN;
FREETMPS;
LEAVE;
}
}
void ssleay_info_cb_invoke(const SSL *ssl, int where, int ret)
{
dSP;
SV *cb_func, *cb_data;
cb_func = cb_data_advanced_get((void*)ssl, "ssleay_info_cb!!func");
cb_data = cb_data_advanced_get((void*)ssl, "ssleay_info_cb!!data");
if ( ! SvROK(cb_func) || (SvTYPE(SvRV(cb_func)) != SVt_PVCV))
croak ("Net::SSLeay: ssleay_info_cb_invoke called, but not set to point to any perl function.\n");
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(PTR2IV(ssl))));
XPUSHs(sv_2mortal(newSViv(where)) );
XPUSHs(sv_2mortal(newSViv(ret)) );
XPUSHs(sv_2mortal(newSVsv(cb_data)));
PUTBACK;
call_sv(cb_func, G_VOID);
SPAGAIN;
PUTBACK;
FREETMPS;
LEAVE;
}
void ssleay_ctx_info_cb_invoke(const SSL *ssl, int where, int ret)
{
dSP;
SV *cb_func, *cb_data;
SSL_CTX *ctx = SSL_get_SSL_CTX(ssl);
cb_func = cb_data_advanced_get(ctx, "ssleay_ctx_info_cb!!func");
cb_data = cb_data_advanced_get(ctx, "ssleay_ctx_info_cb!!data");
if ( ! SvROK(cb_func) || (SvTYPE(SvRV(cb_func)) != SVt_PVCV))
croak ("Net::SSLeay: ssleay_ctx_info_cb_invoke called, but not set to point to any perl function.\n");
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(PTR2IV(ssl))));
XPUSHs(sv_2mortal(newSViv(where)) );
XPUSHs(sv_2mortal(newSViv(ret)) );
XPUSHs(sv_2mortal(newSVsv(cb_data)));
PUTBACK;
call_sv(cb_func, G_VOID);
SPAGAIN;
PUTBACK;
FREETMPS;
LEAVE;
}
/* ============= end of callback stuff, begin helper functions ============== */
time_t ASN1_TIME_timet(ASN1_TIME *asn1t) {
struct tm t;
const char *p = (const char*) asn1t->data;
size_t msec = 0, tz = 0, i, l;
time_t result;
int adj = 0;
if (asn1t->type == V_ASN1_UTCTIME) {
if (asn1t->length<12 || asn1t->length>17) return 0;
if (asn1t->length>12) tz = 12;
} else {
if (asn1t->length<14) return 0;
if (asn1t->length>14) {
if (p[14] == '.') {
msec = 14;
for(i=msec+1;i<asn1t->length && p[i]>='0' && p[i]<='9';i++) ;
if (i<asn1t->length) tz = i;
} else {
tz = 14;
}
}
}
l = msec ? msec : tz ? tz : asn1t->length;
for(i=0;i<l;i++) {
if (p[i]<'0' || p[i]>'9') return 0;
}
/* extract data and time */
memset(&t,0,sizeof(t));
if (asn1t->type == V_ASN1_UTCTIME) { /* YY - two digit year */
t.tm_year = (p[0]-'0')*10 + (p[1]-'0');
if (t.tm_year < 70) t.tm_year += 100;
i=2;
} else { /* YYYY */
t.tm_year = (p[0]-'0')*1000 + (p[1]-'0')*100 + (p[2]-'0')*10 + p[3]-'0';
t.tm_year -= 1900;
i=4;
}
t.tm_mon = (p[i+0]-'0')*10 + (p[i+1]-'0') -1; /* MM, starts with 0 in tm */
t.tm_mday = (p[i+2]-'0')*10 + (p[i+3]-'0'); /* DD */
t.tm_hour = (p[i+4]-'0')*10 + (p[i+5]-'0'); /* hh */
t.tm_min = (p[i+6]-'0')*10 + (p[i+7]-'0'); /* mm */
t.tm_sec = (p[i+8]-'0')*10 + (p[i+9]-'0'); /* ss */
/* skip msec, because time_t does not support it */
if (tz) {
/* TZ is 'Z' or [+-]DDDD and after TZ the string must stop*/
if (p[tz] == 'Z') {
if (asn1t->length>tz+1 ) return 0;
} else if (asn1t->length<tz+5 || (p[tz]!='-' && p[tz]!='+')) {
return 0;
} else {
if (asn1t->length>tz+5 ) return 0;
for(i=tz+1;i<tz+5;i++) {
if (p[i]<'0' || p[i]>'9') return 0;
}
adj = ((p[tz+1]-'0')*10 + (p[tz+2]-'0'))*3600
+ ((p[tz+3]-'0')*10 + (p[tz+4]-'0'))*60;
if (p[tz]=='+') adj*= -1; /* +0500: subtract 5 hours to get UTC */
}
}
result = mktime(&t);
if (result == -1) return 0; /* broken time */
return result + adj + ( t.tm_isdst ? 3600:0 );
}
X509 * find_issuer(X509 *cert,X509_STORE *store, STACK_OF(X509) *chain) {
int i;
X509 *issuer = NULL;
/* search first in the chain */
if (chain) {
for(i=0;i<sk_X509_num(chain);i++) {
if ( X509_check_issued(sk_X509_value(chain,i),cert) == X509_V_OK ) {
TRACE(2,"found issuer in chain");
issuer = sk_X509_value(chain,i);
}
}
}
/* if not in the chain it might be in the store */
if ( !issuer && store ) {
X509_STORE_CTX *stx = X509_STORE_CTX_new();
if (stx && X509_STORE_CTX_init(stx,store,cert,NULL)) {
int ok = X509_STORE_CTX_get1_issuer(&issuer,stx,cert);
if (ok<0) {
int err = ERR_get_error();
if(err) {
TRACE(2,"failed to get issuer: %s",ERR_error_string(err,NULL));
} else {
TRACE(2,"failed to get issuer: unknown error");
}
} else if (ok == 0 ) {
TRACE(2,"failed to get issuer(0)");
} else {
TRACE(2,"got issuer");
}
}
if (stx) X509_STORE_CTX_free(stx);
}
return issuer;
}
/* ============= end of helper functions ============== */
MODULE = Net::SSLeay PACKAGE = Net::SSLeay PREFIX = SSL_
PROTOTYPES: ENABLE
BOOT:
{
MY_CXT_INIT;
LIB_initialized = 0;
#ifdef USE_ITHREADS
MUTEX_INIT(&LIB_init_mutex);
#ifdef OPENSSL_THREADS
/* If we running under ModPerl, we dont need our own thread locking because
* perl threads are not supported under mod-perl, and we can fall back to the thread
* locking built in to mod-ssl
*/
if (!hv_fetch(get_hv("ENV", 1), "MOD_PERL", 8, 0))
openssl_threads_init();
#endif
#endif
/* initialize global shared callback data hash */
MY_CXT.global_cb_data = newHV();
MY_CXT.tid = get_my_thread_id();
PR3("BOOT: tid=%d my_perl=0x%p\n", MY_CXT.tid, my_perl);
}
void
CLONE(...)
CODE:
MY_CXT_CLONE;
/* reset all callback related data as we want to prevent
* cross-thread callbacks
* TODO: later somebody can make the global hash MY_CXT.global_cb_data
* somehow shared between threads
*/
MY_CXT.global_cb_data = newHV();
MY_CXT.tid = get_my_thread_id();
PR3("CLONE: tid=%d my_perl=0x%p\n", MY_CXT.tid, my_perl);
double
constant(name)
char * name
CODE:
errno = 0;
RETVAL = constant(name, strlen(name));
OUTPUT:
RETVAL
int
hello()
CODE:
PR1("\tSSLeay Hello World!\n");
RETVAL = 1;
OUTPUT:
RETVAL
#define REM0 "============= version related functions =============="
unsigned long
SSLeay()
const char *
SSLeay_version(type=0)
int type
#define REM1 "============= SSL CONTEXT functions =============="
SSL_CTX *
SSL_CTX_new()
CODE:
RETVAL = SSL_CTX_new (SSLv23_method());
OUTPUT:
RETVAL
#ifndef OPENSSL_NO_SSL2
#if OPENSSL_VERSION_NUMBER < 0x10000000L
SSL_CTX *
SSL_CTX_v2_new()
CODE:
RETVAL = SSL_CTX_new (SSLv2_method());
OUTPUT:
RETVAL
#endif
#endif
SSL_CTX *
SSL_CTX_v3_new()
CODE:
RETVAL = SSL_CTX_new (SSLv3_method());
OUTPUT:
RETVAL
SSL_CTX *
SSL_CTX_v23_new()
CODE:
RETVAL = SSL_CTX_new (SSLv23_method());
OUTPUT:
RETVAL
SSL_CTX *
SSL_CTX_tlsv1_new()
CODE:
RETVAL = SSL_CTX_new (TLSv1_method());
OUTPUT:
RETVAL
#ifdef SSL_TXT_TLSV1_1
SSL_CTX *
SSL_CTX_tlsv1_1_new()
CODE:
RETVAL = SSL_CTX_new (TLSv1_1_method());
OUTPUT:
RETVAL
#endif
#ifdef SSL_TXT_TLSV1_2
SSL_CTX *
SSL_CTX_tlsv1_2_new()
CODE:
RETVAL = SSL_CTX_new (TLSv1_2_method());
OUTPUT:
RETVAL
#endif
SSL_CTX *
SSL_CTX_new_with_method(meth)
SSL_METHOD * meth
CODE:
RETVAL = SSL_CTX_new (meth);
OUTPUT:
RETVAL
void
SSL_CTX_free(ctx)
SSL_CTX * ctx
CODE:
cb_data_advanced_drop(ctx); /* clean callback related data from global hash */
SSL_CTX_free(ctx);
int
SSL_CTX_add_session(ctx,ses)
SSL_CTX * ctx
SSL_SESSION * ses
int
SSL_CTX_remove_session(ctx,ses)
SSL_CTX * ctx
SSL_SESSION * ses
void
SSL_CTX_flush_sessions(ctx,tm)
SSL_CTX * ctx
long tm
int
SSL_CTX_set_default_verify_paths(ctx)
SSL_CTX * ctx
int
SSL_CTX_load_verify_locations(ctx,CAfile,CApath)
SSL_CTX * ctx
char * CAfile
char * CApath
CODE:
RETVAL = SSL_CTX_load_verify_locations (ctx,
CAfile?(*CAfile?CAfile:NULL):NULL,
CApath?(*CApath?CApath:NULL):NULL
);
OUTPUT:
RETVAL
void
SSL_CTX_set_verify(ctx,mode,callback=&PL_sv_undef)
SSL_CTX * ctx
int mode
SV * callback
CODE:
/* Former versions of SSLeay checked if the callback was a true boolean value
* and didn't call it if it was false. Therefor some people set the callback
* to '0' if they don't want to use it (IO::Socket::SSL for example). Therefor
* we don't execute the callback if it's value isn't something true to retain
* backwards compatibility.
*/
if (callback==NULL || !SvOK(callback) || !SvTRUE(callback)) {
SSL_CTX_set_verify(ctx, mode, NULL);
cb_data_advanced_put(ctx, "ssleay_verify_callback!!func", NULL);
} else {
cb_data_advanced_put(ctx, "ssleay_verify_callback!!func", newSVsv(callback));
SSL_CTX_set_verify(ctx, mode, &ssleay_verify_callback_invoke);
}
int
SSL_get_error(s,ret)
SSL * s
int ret
#define REM10 "============= SSL functions =============="
SSL *
SSL_new(ctx)
SSL_CTX * ctx
void
SSL_free(s)
SSL * s
CODE:
cb_data_advanced_drop(s); /* clean callback related data from global hash */
SSL_free(s);
#if 0 /* this seems to be gone in 0.9.0 */
void
SSL_debug(file)
char * file
#endif
int
SSL_accept(s)
SSL * s
void
SSL_clear(s)
SSL * s
int
SSL_connect(s)
SSL * s
#if defined(WIN32)
int
SSL_set_fd(s,fd)
SSL * s
perl_filehandle_t fd
CODE:
RETVAL = SSL_set_fd(s,_get_osfhandle(fd));
OUTPUT:
RETVAL
int
SSL_set_rfd(s,fd)
SSL * s
perl_filehandle_t fd
CODE:
RETVAL = SSL_set_rfd(s,_get_osfhandle(fd));
OUTPUT:
RETVAL
int
SSL_set_wfd(s,fd)
SSL * s
perl_filehandle_t fd
CODE:
RETVAL = SSL_set_wfd(s,_get_osfhandle(fd));
OUTPUT:
RETVAL
#else
int
SSL_set_fd(s,fd)
SSL * s
perl_filehandle_t fd
int
SSL_set_rfd(s,fd)
SSL * s
perl_filehandle_t fd
int
SSL_set_wfd(s,fd)
SSL * s
perl_filehandle_t fd
#endif
int
SSL_get_fd(s)
SSL * s
AV *
SSL_read(s,max=32768)
SSL * s
int max
PREINIT:
char *buf;
int got;
PPCODE:
New(0, buf, max, char);
got = SSL_read(s, buf, max);
/* If in list context, return 2-item list:
* first return value: data gotten, or undef on error (got<0)
* second return value: result from SSL_read()
*/
if (GIMME_V==G_ARRAY) {
EXTEND(SP, 2);
PUSHs(sv_2mortal(got>=0 ? newSVpvn(buf, got) : newSV(0)));
PUSHs(sv_2mortal(newSViv(got)));
/* If in scalar or void context, return data gotten, or undef on error. */
} else {
EXTEND(SP, 1);
PUSHs(sv_2mortal(got>=0 ? newSVpvn(buf, got) : newSV(0)));
}
Safefree(buf);
void
SSL_peek(s,max=32768)
SSL * s
int max
PREINIT:
char *buf;
int got;
PPCODE:
New(0, buf, max, char);
got = SSL_peek(s, buf, max);
/* If in list context, return 2-item list:
* first return value: data gotten, or undef on error (got<0)
* second return value: result from SSL_peek()
*/
if (GIMME_V==G_ARRAY) {
EXTEND(SP, 2);
PUSHs(sv_2mortal(got>=0 ? newSVpvn(buf, got) : newSV(0)));
PUSHs(sv_2mortal(newSViv(got)));
/* If in scalar or void context, return data gotten, or undef on error. */
} else {
EXTEND(SP, 1);
PUSHs(sv_2mortal(got>=0 ? newSVpvn(buf, got) : newSV(0)));
}
Safefree(buf);
int
SSL_write(s,buf)
SSL * s
PREINIT:
STRLEN len;
INPUT:
char * buf = SvPV( ST(1), len);
CODE:
RETVAL = SSL_write (s, buf, (int)len);
OUTPUT:
RETVAL
int
SSL_write_partial(s,from,count,buf)
SSL * s
int from
int count
PREINIT:
STRLEN ulen;
IV len;
INPUT:
char * buf = SvPV( ST(3), ulen);
CODE:
/*
if (SvROK( ST(3) )) {
SV* t = SvRV( ST(3) );
buf = SvPV( t, len);
} else
buf = SvPV( ST(3), len);
*/
PR4("write_partial from=%d count=%d len=%ul\n",from,count,ulen);
/*PR2("buf='%s'\n",&buf[from]); / * too noisy */
len = (IV)ulen;
len -= from;
if (len < 0) {
croak("from beyound end of buffer");
RETVAL = -1;
} else
RETVAL = SSL_write (s, &(buf[from]), (count<=len)?count:len);
OUTPUT:
RETVAL
int
SSL_use_RSAPrivateKey(s,rsa)
SSL * s
RSA * rsa
int
SSL_use_RSAPrivateKey_ASN1(s,d,len)
SSL * s
unsigned char * d
long len
int
SSL_use_RSAPrivateKey_file(s,file,type)
SSL * s
char * file
int type
int
SSL_CTX_use_RSAPrivateKey_file(ctx,file,type)
SSL_CTX * ctx
char * file
int type
int
SSL_use_PrivateKey(s,pkey)
SSL * s
EVP_PKEY * pkey
int
SSL_use_PrivateKey_ASN1(pk,s,d,len)
int pk
SSL * s
unsigned char * d
long len
int
SSL_use_PrivateKey_file(s,file,type)
SSL * s
char * file
int type
int
SSL_CTX_use_PrivateKey_file(ctx,file,type)
SSL_CTX * ctx
char * file
int type
int
SSL_use_certificate(s,x)
SSL * s
X509 * x
int
SSL_use_certificate_ASN1(s,d,len)
SSL * s
unsigned char * d
long len
int
SSL_use_certificate_file(s,file,type)
SSL * s
char * file
int type
int
SSL_CTX_use_certificate_file(ctx,file,type)
SSL_CTX * ctx
char * file
int type
const char *
SSL_state_string(s)
SSL * s
const char *
SSL_rstate_string(s)
SSL * s
const char *
SSL_state_string_long(s)
SSL * s
const char *
SSL_rstate_string_long(s)
SSL * s
long
SSL_get_time(ses)
SSL_SESSION * ses
long
SSL_set_time(ses,t)
SSL_SESSION * ses
long t
long
SSL_get_timeout(ses)
SSL_SESSION * ses
long
SSL_set_timeout(ses,t)
SSL_SESSION * ses
long t
void
SSL_copy_session_id(to,from)
SSL * to
SSL * from
void
SSL_set_read_ahead(s,yes=1)
SSL * s
int yes
int
SSL_get_read_ahead(s)
SSL * s
int
SSL_pending(s)
SSL * s
int
SSL_CTX_set_cipher_list(s,str)
SSL_CTX * s
char * str
const char *
SSL_get_cipher_list(s,n)
SSL * s
int n
int
SSL_set_cipher_list(s,str)
SSL * s
char * str
const char *
SSL_get_cipher(s)
SSL * s
void
SSL_get_shared_ciphers(s,ignored_param1=0,ignored_param2=0)
SSL *s
int ignored_param1
int ignored_param2
PREINIT:
char buf[8192];
CODE:
ST(0) = sv_newmortal(); /* undef to start with */
if(SSL_get_shared_ciphers(s, buf, sizeof(buf)))
sv_setpvn(ST(0), buf, strlen(buf));
X509 *
SSL_get_peer_certificate(s)
SSL * s
void
SSL_get_peer_cert_chain(s)
SSL * s
PREINIT:
STACK_OF(X509) *chain = NULL;
X509 *x;
int i;
PPCODE:
chain = SSL_get_peer_cert_chain(s);
if( chain == NULL ) {
XSRETURN_EMPTY;
}
for (i=0; i<sk_X509_num(chain); i++) {
x = sk_X509_value(chain, i);
XPUSHs(sv_2mortal(newSViv(PTR2IV(x))));
}
void
SSL_set_verify(s,mode,callback)
SSL * s
int mode
SV * callback
CODE:
if (callback==NULL || !SvOK(callback)) {
SSL_set_verify(s, mode, NULL);
cb_data_advanced_put(s, "ssleay_verify_callback!!func", NULL);
}
else {
cb_data_advanced_put(s, "ssleay_verify_callback!!func", newSVsv(callback));
SSL_set_verify(s, mode, &ssleay_verify_callback_invoke);
}
void
SSL_set_bio(s,rbio,wbio)
SSL * s
BIO * rbio
BIO * wbio
BIO *
SSL_get_rbio(s)
SSL * s
BIO *
SSL_get_wbio(s)
SSL * s
SSL_SESSION *
SSL_SESSION_new()
int
SSL_SESSION_print(fp,ses)
BIO * fp
SSL_SESSION * ses
void
SSL_SESSION_free(ses)
SSL_SESSION * ses
int
i2d_SSL_SESSION(in,pp)
SSL_SESSION * in
unsigned char * &pp
int
SSL_set_session(to,ses)
SSL * to
SSL_SESSION * ses
#if OPENSSL_VERSION_NUMBER < 0x0090707fL
#define REM3 "NOTE: before 0.9.7g"
SSL_SESSION *
d2i_SSL_SESSION(a,pp,length)
SSL_SESSION * &a
unsigned char * &pp
long length
#else
SSL_SESSION *
d2i_SSL_SESSION(a,pp,length)
SSL_SESSION * &a
const unsigned char * &pp
long length
#endif
#define REM30 "SSLeay-0.9.0 defines these as macros. I expand them here for safety's sake"
SSL_SESSION *
SSL_get_session(s)
SSL * s
ALIAS:
SSL_get0_session = 1
SSL_SESSION *
SSL_get1_session(s)
SSL * s
X509 *
SSL_get_certificate(s)
SSL * s
#if OPENSSL_VERSION_NUMBER >= 0x0090806fL
#define REM18 "NOTE: requires 0.9.8f+"
SSL_CTX *
SSL_get_SSL_CTX(s)
SSL * s
SSL_CTX *
SSL_set_SSL_CTX(SSL *ssl, SSL_CTX* ctx)
long
SSL_ctrl(ssl,cmd,larg,parg)
SSL * ssl
int cmd
long larg
char * parg
#endif
long
SSL_CTX_ctrl(ctx,cmd,larg,parg)
SSL_CTX * ctx
int cmd
long larg
char * parg
long
SSL_get_options(ssl)
SSL * ssl
long
SSL_set_options(ssl,op)
SSL * ssl
long op
long
SSL_CTX_get_options(ctx)
SSL_CTX * ctx
long
SSL_CTX_set_options(ctx,op)
SSL_CTX * ctx
long op
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
struct lhash_st_SSL_SESSION *
SSL_CTX_sessions(ctx)
SSL_CTX * ctx
#else
LHASH *
SSL_CTX_sessions(ctx)
SSL_CTX * ctx
CODE:
/* NOTE: This should be deprecated. Corresponding macro was removed from ssl.h as of 0.9.2 */
if (ctx == NULL) croak("NULL SSL context passed as argument.");
RETVAL = ctx -> sessions;
OUTPUT:
RETVAL
#endif
unsigned long
SSL_CTX_sess_number(ctx)
SSL_CTX * ctx
int
SSL_CTX_sess_connect(ctx)
SSL_CTX * ctx
int
SSL_CTX_sess_connect_good(ctx)
SSL_CTX * ctx
int
SSL_CTX_sess_connect_renegotiate(ctx)
SSL_CTX * ctx
int
SSL_CTX_sess_accept(ctx)
SSL_CTX * ctx
int
SSL_CTX_sess_accept_renegotiate(ctx)
SSL_CTX * ctx
int
SSL_CTX_sess_accept_good(ctx)
SSL_CTX * ctx
int
SSL_CTX_sess_hits(ctx)
SSL_CTX * ctx
int
SSL_CTX_sess_cb_hits(ctx)
SSL_CTX * ctx
int
SSL_CTX_sess_misses(ctx)
SSL_CTX * ctx
int
SSL_CTX_sess_timeouts(ctx)
SSL_CTX * ctx
int
SSL_CTX_sess_cache_full(ctx)
SSL_CTX * ctx
int
SSL_CTX_sess_get_cache_size(ctx)
SSL_CTX * ctx
long
SSL_CTX_sess_set_cache_size(ctx,size)
SSL_CTX * ctx
int size
int
SSL_want(s)
SSL * s
int
SSL_state(s)
SSL * s
#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
long
SSL_set_tlsext_host_name(SSL *ssl, const char *name)
const char *
SSL_get_servername(const SSL *s, int type=TLSEXT_NAMETYPE_host_name)
int
SSL_get_servername_type(const SSL *s)
void
SSL_CTX_set_tlsext_servername_callback(ctx,callback=&PL_sv_undef,data=&PL_sv_undef)
SSL_CTX * ctx
SV * callback
SV * data
CODE:
if (callback==NULL || !SvOK(callback)) {
SSL_CTX_set_tlsext_servername_callback(ctx, NULL);
SSL_CTX_set_tlsext_servername_arg(ctx, NULL);
cb_data_advanced_put(ctx, "tlsext_servername_callback!!data", NULL);
cb_data_advanced_put(ctx, "tlsext_servername_callback!!func", NULL);
} else {
cb_data_advanced_put(ctx, "tlsext_servername_callback!!data", newSVsv(data));
cb_data_advanced_put(ctx, "tlsext_servername_callback!!func", newSVsv(callback));
SSL_CTX_set_tlsext_servername_callback(ctx, &tlsext_servername_callback_invoke);
SSL_CTX_set_tlsext_servername_arg(ctx, (void*)ctx);
}
#endif
BIO_METHOD *
BIO_f_ssl()
BIO_METHOD *
BIO_s_mem()
unsigned long
ERR_get_error()
unsigned long
ERR_peek_error()
void
ERR_put_error(lib,func,reason,file,line)
int lib
int func
int reason
char * file
int line
void
ERR_clear_error()
char *
ERR_error_string(error,buf=NULL)
unsigned long error
char * buf
CODE:
RETVAL = ERR_error_string(error,buf);
OUTPUT:
RETVAL
void
SSL_load_error_strings()
void
ERR_load_crypto_strings()
int
SSL_FIPS_mode_set(int onoff)
CODE:
#ifdef USE_ITHREADS
MUTEX_LOCK(&LIB_init_mutex);
#endif
#ifdef OPENSSL_FIPS
RETVAL = FIPS_mode_set(onoff);
if (!RETVAL)
{
ERR_load_crypto_strings();
ERR_print_errors_fp(stderr);
}
#else
RETVAL = 1;
fprintf(stderr, "SSL_FIPS_mode_set not available: OpenSSL not compiled with FIPS support\n");
#endif
#ifdef USE_ITHREADS
MUTEX_UNLOCK(&LIB_init_mutex);
#endif
OUTPUT:
RETVAL
int
SSL_library_init()
ALIAS:
SSLeay_add_ssl_algorithms = 1
OpenSSL_add_ssl_algorithms = 2
add_ssl_algorithms = 3
CODE:
#ifdef USE_ITHREADS
MUTEX_LOCK(&LIB_init_mutex);
#endif
RETVAL = 0;
if (!LIB_initialized) {
RETVAL = SSL_library_init();
LIB_initialized = 1;
}
#ifdef USE_ITHREADS
MUTEX_UNLOCK(&LIB_init_mutex);
#endif
OUTPUT:
RETVAL
#if OPENSSL_VERSION_NUMBER >= 0x0090700fL
#define REM5 "NOTE: requires 0.9.7+"
void
ENGINE_load_builtin_engines()
void
ENGINE_register_all_complete()
ENGINE*
ENGINE_by_id(id)
char * id
int
ENGINE_set_default(e, flags)
ENGINE * e
int flags
#endif
void
ERR_load_SSL_strings()
void
ERR_load_RAND_strings()
int
RAND_bytes(buf, num)
SV *buf
int num
PREINIT:
int rc;
unsigned char *random;
CODE:
New(0, random, num, unsigned char);
rc = RAND_bytes(random, num);
sv_setpvn(buf, (const char*)random, num);
Safefree(random);
RETVAL = rc;
OUTPUT:
RETVAL
int
RAND_pseudo_bytes(buf, num)
SV *buf
int num
PREINIT:
int rc;
unsigned char *random;
CODE:
New(0, random, num, unsigned char);
rc = RAND_pseudo_bytes(random, num);
sv_setpvn(buf, (const char*)random, num);
Safefree(random);
RETVAL = rc;
OUTPUT:
RETVAL
void
RAND_add(buf, num, entropy)
SV *buf
int num
double entropy
PREINIT:
STRLEN len;
CODE:
RAND_add((const void *)SvPV(buf, len), num, entropy);
int
RAND_poll()
int
RAND_status()
SV *
RAND_file_name(num)
size_t num
PREINIT:
char *buf;
CODE:
New(0, buf, num, char);
if (!RAND_file_name(buf, num)) {
Safefree(buf);
XSRETURN_UNDEF;
}
RETVAL = newSVpv(buf, 0);
Safefree(buf);
OUTPUT:
RETVAL
void
RAND_seed(buf)
PREINIT:
STRLEN len;
INPUT:
char * buf = SvPV( ST(1), len);
CODE:
RAND_seed (buf, (int)len);
void
RAND_cleanup()
int
RAND_load_file(file_name, how_much)
char * file_name
int how_much
int
RAND_write_file(file_name)
char * file_name
#define REM40 "Minimal X509 stuff..., this is a bit ugly and should be put in its own modules Net::SSLeay::X509.pm"
X509_NAME*
X509_get_issuer_name(cert)
X509 * cert
X509_NAME*
X509_get_subject_name(cert)
X509 * cert
int
X509_set_issuer_name(X509 *x, X509_NAME *name)
int
X509_set_subject_name(X509 *x, X509_NAME *name)
int
X509_set_version(X509 *x, long version)
int
X509_set_pubkey(X509 *x, EVP_PKEY *pkey)
long
X509_get_version(X509 *x)
EVP_PKEY *
X509_get_pubkey(X509 *x)
ASN1_INTEGER *
X509_get_serialNumber(X509 *x)
int
X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial)
int
X509_certificate_type(X509 *x, EVP_PKEY *pubkey=NULL);
int
X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md)
int
X509_verify(X509 *x, EVP_PKEY *r)
X509_NAME *
X509_NAME_new()
unsigned long
X509_NAME_hash(X509_NAME *name)
void
X509_NAME_oneline(name)
X509_NAME * name
PREINIT:
char * buf;
CODE:
ST(0) = sv_newmortal(); /* Undefined to start with */
if ((buf = X509_NAME_oneline(name, NULL, 0))) {
sv_setpvn( ST(0), buf, strlen(buf));
OPENSSL_free(buf); /* mem was allocated by openssl */
}
void
X509_NAME_print_ex(name,flags=XN_FLAG_RFC2253,utf8_decode=0)
X509_NAME * name
unsigned long flags
int utf8_decode
PREINIT:
char * buf;
BIO * bp;
int n, i, ident=0;
CODE:
ST(0) = sv_newmortal(); /* undef to start with */
bp = BIO_new(BIO_s_mem());
if (bp) {
if (X509_NAME_print_ex(bp, name, ident, flags)) {
n = BIO_ctrl_pending(bp);
New(0, buf, n, char);
if (buf) {
i = BIO_read(bp,buf,n);
if (i>=0 && i<=n) {
sv_setpvn(ST(0), buf, i);
if (utf8_decode) sv_utf8_decode(ST(0));
}
Safefree(buf);
}
}
BIO_free(bp);
}
void
X509_NAME_get_text_by_NID(name,nid)
X509_NAME * name
int nid
PREINIT:
char* buf;
int length;
CODE:
ST(0) = sv_newmortal(); /* Undefined to start with */
length = X509_NAME_get_text_by_NID(name, nid, NULL, 0);
if (length>=0) {
New(0, buf, length+1, char);
if (X509_NAME_get_text_by_NID(name, nid, buf, length + 1)>=0)
sv_setpvn( ST(0), buf, length);
Safefree(buf);
}
#if OPENSSL_VERSION_NUMBER >= 0x0090500fL
#define REM17 "requires 0.9.5+"
int
X509_NAME_add_entry_by_NID(name,nid,type,bytes,loc=-1,set=0)
X509_NAME *name
int nid
int type
int loc
int set
PREINIT:
STRLEN len;
INPUT:
unsigned char *bytes = (unsigned char *)SvPV(ST(3), len);
CODE:
RETVAL = X509_NAME_add_entry_by_NID(name,nid,type,bytes,len,loc,set);
OUTPUT:
RETVAL
int
X509_NAME_add_entry_by_OBJ(name,obj,type,bytes,loc=-1,set=0)
X509_NAME *name
ASN1_OBJECT *obj
int type
int loc
int set
PREINIT:
STRLEN len;
INPUT:
unsigned char *bytes = (unsigned char *)SvPV(ST(3), len);
CODE:
RETVAL = X509_NAME_add_entry_by_OBJ(name,obj,type,bytes,len,loc,set);
OUTPUT:
RETVAL
int
X509_NAME_add_entry_by_txt(name,field,type,bytes,loc=-1,set=0)
X509_NAME *name
char *field
int type
int loc
int set
PREINIT:
STRLEN len;
INPUT:
unsigned char *bytes = (unsigned char *)SvPV(ST(3), len);
CODE:
RETVAL = X509_NAME_add_entry_by_txt(name,field,type,bytes,len,loc,set);
OUTPUT:
RETVAL
#endif
int
X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b)
int
X509_NAME_entry_count(X509_NAME *name)
X509_NAME_ENTRY *
X509_NAME_get_entry(X509_NAME *name, int loc)
ASN1_STRING *
X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *ne)
ASN1_OBJECT *
X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *ne)
void
X509_CRL_free(X509_CRL *x)
X509_CRL *
X509_CRL_new()
#if OPENSSL_VERSION_NUMBER >= 0x0090700fL
#define REM19 "requires 0.9.7+"
int
X509_CRL_set_version(X509_CRL *x, long version)
int
X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name)
int
X509_CRL_set_lastUpdate(X509_CRL *x, ASN1_TIME *tm)
int
X509_CRL_set_nextUpdate(X509_CRL *x, ASN1_TIME *tm)
int
X509_CRL_sort(X509_CRL *x)
#endif
long
X509_CRL_get_version(X509_CRL *x)
X509_NAME *
X509_CRL_get_issuer(X509_CRL *x)
ASN1_TIME *
X509_CRL_get_lastUpdate(X509_CRL *x)
ASN1_TIME *
X509_CRL_get_nextUpdate(X509_CRL *x)
int
X509_CRL_verify(X509_CRL *a, EVP_PKEY *r)
int
X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md)
#if OPENSSL_VERSION_NUMBER >= 0x0090700fL
#define REM20 "requires 0.9.7+"
int
P_X509_CRL_set_serial(crl,crl_number)
X509_CRL *crl
ASN1_INTEGER * crl_number;
CODE:
RETVAL = 0;
if (crl && crl_number)
if (X509_CRL_add1_ext_i2d(crl, NID_crl_number, crl_number, 0, 0)) RETVAL = 1;
OUTPUT:
RETVAL
ASN1_INTEGER *
P_X509_CRL_get_serial(crl)
X509_CRL *crl
INIT:
int i;
CODE:
RETVAL = (ASN1_INTEGER *)X509_CRL_get_ext_d2i(crl, NID_crl_number, &i, NULL);
if (!RETVAL || i==-1) XSRETURN_UNDEF;
OUTPUT:
RETVAL
void
P_X509_CRL_add_revoked_serial_hex(crl,serial_hex,rev_time,reason_code=0,comp_time=NULL)
X509_CRL *crl
char * serial_hex
ASN1_TIME *rev_time
long reason_code
ASN1_TIME *comp_time
PREINIT:
BIGNUM *bn = NULL;
ASN1_INTEGER *sn;
X509_REVOKED *rev;
ASN1_ENUMERATED *rsn = NULL;
int rv;
PPCODE:
rv=0;
rev = X509_REVOKED_new();
if (rev) {
if (BN_hex2bn(&bn, serial_hex)) {
sn = BN_to_ASN1_INTEGER(bn, NULL);
if (sn) {
X509_REVOKED_set_serialNumber(rev, sn);
ASN1_INTEGER_free(sn);
rv = 1;
}
BN_free(bn);
}
}
if (!rv) XSRETURN_IV(0);
if (!rev_time) XSRETURN_IV(0);
if (!X509_REVOKED_set_revocationDate(rev, rev_time)) XSRETURN_IV(0);
if(reason_code) {
rv = 0;
rsn = ASN1_ENUMERATED_new();
if (rsn) {
if (ASN1_ENUMERATED_set(rsn, reason_code))
if (X509_REVOKED_add1_ext_i2d(rev, NID_crl_reason, rsn, 0, 0))
rv=1;
ASN1_ENUMERATED_free(rsn);
}
if (!rv) XSRETURN_IV(0);
}
if(comp_time) {
X509_REVOKED_add1_ext_i2d(rev, NID_invalidity_date, comp_time, 0, 0);
}
if(!X509_CRL_add0_revoked(crl, rev)) XSRETURN_IV(0);
XSRETURN_IV(1);
#endif
X509_REQ *
X509_REQ_new()
void
X509_REQ_free(X509_REQ *x)
X509_NAME *
X509_REQ_get_subject_name(X509_REQ *x)
int
X509_REQ_set_subject_name(X509_REQ *x, X509_NAME *name)
int
X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey)
EVP_PKEY *
X509_REQ_get_pubkey(X509_REQ *x)
int
X509_REQ_sign(X509_REQ *x, EVP_PKEY *pk, const EVP_MD *md)
int
X509_REQ_verify(X509_REQ *x, EVP_PKEY *r)
int
X509_REQ_set_version(X509_REQ *x, long version)
long
X509_REQ_get_version(X509_REQ *x)
int
X509_REQ_get_attr_count(const X509_REQ *req);
int
X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid, int lastpos=-1)
int
X509_REQ_get_attr_by_OBJ(const X509_REQ *req, ASN1_OBJECT *obj, int lastpos=-1)
int
X509_REQ_add1_attr_by_NID(req,nid,type,bytes)
X509_REQ *req
int nid
int type
PREINIT:
STRLEN len;
INPUT:
unsigned char *bytes = (unsigned char *)SvPV(ST(3), len);
CODE:
RETVAL = X509_REQ_add1_attr_by_NID(req,nid,type,bytes,len);
OUTPUT:
RETVAL
#if OPENSSL_VERSION_NUMBER >= 0x0090700fL
#define REM21 "requires 0.9.7+"
void
P_X509_REQ_get_attr(req,n)
X509_REQ *req
int n
INIT:
X509_ATTRIBUTE * att;
int count, i;
ASN1_STRING * s;
PPCODE:
att = X509_REQ_get_attr(req,n);
if (att->single) {
s = (att->value.single->value.asn1_string);
XPUSHs(sv_2mortal(newSViv(PTR2IV(s))));
}
else {
count = sk_ASN1_TYPE_num(att->value.set);
for (i=0; i<count; i++) {
s = (sk_ASN1_TYPE_value(att->value.set, i)->value.asn1_string);
XPUSHs(sv_2mortal(newSViv(PTR2IV(s))));
}
}
#endif
int
P_X509_REQ_add_extensions(x,...)
X509_REQ *x
PREINIT:
int i=1;
int nid;
char *data;
X509_EXTENSION *ex;
STACK_OF(X509_EXTENSION) *stack;
CODE:
if (items>1) {
RETVAL = 1;
stack = sk_X509_EXTENSION_new_null();
while(i+1<items) {
nid = SvIV(ST(i));
data = SvPV_nolen(ST(i+1));
i+=2;
ex = X509V3_EXT_conf_nid(NULL, NULL, nid, data);
if (ex)
sk_X509_EXTENSION_push(stack, ex);
else
RETVAL = 0;
}
X509_REQ_add_extensions(x, stack);
sk_X509_EXTENSION_pop_free(stack, X509_EXTENSION_free);
}
else
RETVAL = 0;
OUTPUT:
RETVAL
int
P_X509_add_extensions(x,ca_cert,...)
X509 *x
X509 *ca_cert
PREINIT:
int i=2;
int nid;
char *data;
X509_EXTENSION *ex;
X509V3_CTX ctx;
CODE:
if (items>1) {
RETVAL = 1;
while(i+1<items) {
nid = SvIV(ST(i));
data = SvPV_nolen(ST(i+1));
i+=2;
X509V3_set_ctx(&ctx, ca_cert, x, NULL, NULL, 0);
ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, data);
if (ex) {
X509_add_ext(x,ex,-1);
X509_EXTENSION_free(ex);
}
else {
warn("failure during X509V3_EXT_conf_nid() for nid=%d\n", nid);
ERR_print_errors_fp(stderr);
RETVAL = 0;
}
}
}
else
RETVAL = 0;
OUTPUT:
RETVAL
void
P_X509_copy_extensions(x509_req,x509,override=1)
X509_REQ *x509_req
X509 *x509
int override
PREINIT:
STACK_OF(X509_EXTENSION) *exts = NULL;
X509_EXTENSION *ext, *tmpext;
ASN1_OBJECT *obj;
int i, idx, ret = 1;
PPCODE:
if (!x509 || !x509_req) XSRETURN_IV(0);
exts = X509_REQ_get_extensions(x509_req);
for(i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
ext = sk_X509_EXTENSION_value(exts, i);
obj = X509_EXTENSION_get_object(ext);
idx = X509_get_ext_by_OBJ(x509, obj, -1);
/* Does extension exist? */
if (idx != -1) {
if (override) continue; /* don't override existing extension */
/* Delete all extensions of same type */
do {
tmpext = X509_get_ext(x509, idx);
X509_delete_ext(x509, idx);
X509_EXTENSION_free(tmpext);
idx = X509_get_ext_by_OBJ(x509, obj, -1);
} while (idx != -1);
}
if (!X509_add_ext(x509, ext, -1)) ret = 0;
}
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
XSRETURN_IV(ret);
X509 *
X509_STORE_CTX_get_current_cert(x509_store_ctx)
X509_STORE_CTX * x509_store_ctx
void *
X509_STORE_CTX_get_ex_data(x509_store_ctx,idx)
X509_STORE_CTX * x509_store_ctx
int idx
void
X509_get_fingerprint(cert,type)
X509 * cert
char * type
PREINIT:
const EVP_MD *digest_tp = NULL;
unsigned char digest[EVP_MAX_MD_SIZE];
unsigned int dsz, k = 0;
char text[EVP_MAX_MD_SIZE * 3 + 1];
CODE:
if (!k && !strcmp(type,"md5")) {
k = 1; digest_tp = EVP_md5();
}
if (!k && !strcmp(type,"sha1")) {
k = 1; digest_tp = EVP_sha1();
}
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#ifndef OPENSSL_NO_SHA256
if (!k && !strcmp(type,"sha256")) {
k = 1; digest_tp = EVP_sha256();
}
#endif
#endif
if (!k && !strcmp(type,"ripemd160")) {
k = 1; digest_tp = EVP_ripemd160();
}
if (!k) /* Default digest */
digest_tp = EVP_sha1();
if ( digest_tp == NULL ) {
/* Out of memory */
XSRETURN_UNDEF;
}
if (!X509_digest(cert, digest_tp, digest, &dsz)) {
/* Out of memory */
XSRETURN_UNDEF;
}
text[0] = '\0';
for(k=0; k<dsz; k++) {
sprintf(&text[strlen(text)], "%02X:", digest[k]);
}
text[strlen(text)-1] = '\0';
ST(0) = sv_newmortal(); /* Undefined to start with */
sv_setpvn( ST(0), text, strlen(text));
void
X509_get_subjectAltNames(cert)
X509 * cert
PPCODE:
int i, j, count = 0;
X509_EXTENSION *subjAltNameExt = NULL;
STACK_OF(GENERAL_NAME) *subjAltNameDNs = NULL;
GENERAL_NAME *subjAltNameDN = NULL;
int num_gnames;
if ( (i = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1)) >= 0
&& (subjAltNameExt = X509_get_ext(cert, i))
&& (subjAltNameDNs = X509V3_EXT_d2i(subjAltNameExt)))
{
num_gnames = sk_GENERAL_NAME_num(subjAltNameDNs);
for (j = 0; j < num_gnames; j++)
{
subjAltNameDN = sk_GENERAL_NAME_value(subjAltNameDNs, j);
switch (subjAltNameDN->type)
{
case GEN_OTHERNAME:
EXTEND(SP, 2);
count++;
PUSHs(sv_2mortal(newSViv(subjAltNameDN->type)));
PUSHs(sv_2mortal(newSVpv((const char*)ASN1_STRING_data(subjAltNameDN->d.otherName->value->value.utf8string), ASN1_STRING_length(subjAltNameDN->d.otherName->value->value.utf8string))));
break;
case GEN_EMAIL:
case GEN_DNS:
case GEN_URI:
EXTEND(SP, 2);
count++;
PUSHs(sv_2mortal(newSViv(subjAltNameDN->type)));
PUSHs(sv_2mortal(newSVpv((const char*)ASN1_STRING_data(subjAltNameDN->d.ia5), ASN1_STRING_length(subjAltNameDN->d.ia5))));
break;
case GEN_DIRNAME:
{
char * buf = X509_NAME_oneline(subjAltNameDN->d.dirn, NULL, 0);
EXTEND(SP, 2);
count++;
PUSHs(sv_2mortal(newSViv(subjAltNameDN->type)));
PUSHs(sv_2mortal(newSVpv((buf), strlen((buf)))));
break;
}
case GEN_IPADD:
EXTEND(SP, 2);
count++;
PUSHs(sv_2mortal(newSViv(subjAltNameDN->type)));
PUSHs(sv_2mortal(newSVpv((const char*)subjAltNameDN->d.ip->data, subjAltNameDN->d.ip->length)));
break;
}
}
}
XSRETURN(count * 2);
#if OPENSSL_VERSION_NUMBER >= 0x0090700fL
void
P_X509_get_crl_distribution_points(cert)
X509 * cert
INIT:
GENERAL_NAMES *gnames;
GENERAL_NAME *gn;
STACK_OF(DIST_POINT) *points;
DIST_POINT *p;
int i, j;
PPCODE:
points = X509_get_ext_d2i(cert, NID_crl_distribution_points, NULL, NULL);
if (points)
for (i = 0; i < sk_DIST_POINT_num(points); i++) {
p = sk_DIST_POINT_value(points, i);
if (!p->distpoint)
continue;
if (p->distpoint->type == 0) {
/* full name */
gnames = p->distpoint->name.fullname;
for (j = 0; j < sk_GENERAL_NAME_num(gnames); j++) {
gn = sk_GENERAL_NAME_value(gnames, j);
if (gn->type == GEN_URI) {
XPUSHs(sv_2mortal(newSVpv((char*)ASN1_STRING_data(gn->d.ia5),ASN1_STRING_length(gn->d.ia5))));
}
}
}
else {
/* relative name - not supported */
/* XXX-TODO: the code below is just an idea; do not enable it without proper test case
BIO *bp;
char *buf;
int n;
X509_NAME ntmp;
ntmp.entries = p->distpoint->name.relativename;
bp = BIO_new(BIO_s_mem());
if (bp) {
X509_NAME_print_ex(bp, &ntmp, 0, XN_FLAG_RFC2253);
n = BIO_ctrl_pending(bp);
New(0, buf, n, char);
if (buf) {
j = BIO_read(bp,buf,n);
if (j>=0 && j<=n) XPUSHs(sv_2mortal(newSVpvn(buf,j)));
Safefree(buf);
}
BIO_free(bp);
}
*/
}
}
void
P_X509_get_ocsp_uri(cert)
X509 * cert
PPCODE:
AUTHORITY_INFO_ACCESS *info;
int i;
info = X509_get_ext_d2i(cert, NID_info_access, NULL, NULL);
if (!info) XSRETURN_UNDEF;
for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) {
ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i);
if (OBJ_obj2nid(ad->method) == NID_ad_OCSP
&& ad->location->type == GEN_URI) {
XPUSHs(sv_2mortal(newSVpv(
(char*)ASN1_STRING_data(ad->location->d.uniformResourceIdentifier),
ASN1_STRING_length(ad->location->d.uniformResourceIdentifier)
)));
if (GIMME == G_SCALAR) break; /* get only first */
}
}
void
P_X509_get_ext_key_usage(cert,format=0)
X509 * cert
int format
PREINIT:
EXTENDED_KEY_USAGE *extusage;
int i, nid;
char buffer[100]; /* openssl doc: a buffer length of 80 should be more than enough to handle any OID encountered in practice */
ASN1_OBJECT *o;
PPCODE:
extusage = X509_get_ext_d2i(cert, NID_ext_key_usage, NULL, NULL);
for(i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) {
o = sk_ASN1_OBJECT_value(extusage,i);
nid = OBJ_obj2nid(o);
OBJ_obj2txt(buffer, sizeof(buffer)-1, o, 1);
if(format==0)
XPUSHs(sv_2mortal(newSVpv(buffer,0))); /* format 0: oid */
else if(format==1 && nid>0)
XPUSHs(sv_2mortal(newSViv(nid))); /* format 1: nid */
else if(format==2 && nid>0)
XPUSHs(sv_2mortal(newSVpv(OBJ_nid2sn(nid),0))); /* format 2: shortname */
else if(format==3 && nid>0)
XPUSHs(sv_2mortal(newSVpv(OBJ_nid2ln(nid),0))); /* format 3: longname */
}
#endif
void
P_X509_get_key_usage(cert)
X509 * cert
INIT:
ASN1_BIT_STRING * u;
PPCODE:
u = X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL);
if (u) {
if (ASN1_BIT_STRING_get_bit(u,0)) XPUSHs(sv_2mortal(newSVpv("digitalSignature",0)));
if (ASN1_BIT_STRING_get_bit(u,1)) XPUSHs(sv_2mortal(newSVpv("nonRepudiation",0)));
if (ASN1_BIT_STRING_get_bit(u,2)) XPUSHs(sv_2mortal(newSVpv("keyEncipherment",0)));
if (ASN1_BIT_STRING_get_bit(u,3)) XPUSHs(sv_2mortal(newSVpv("dataEncipherment",0)));
if (ASN1_BIT_STRING_get_bit(u,4)) XPUSHs(sv_2mortal(newSVpv("keyAgreement",0)));
if (ASN1_BIT_STRING_get_bit(u,5)) XPUSHs(sv_2mortal(newSVpv("keyCertSign",0)));
if (ASN1_BIT_STRING_get_bit(u,6)) XPUSHs(sv_2mortal(newSVpv("cRLSign",0)));
if (ASN1_BIT_STRING_get_bit(u,7)) XPUSHs(sv_2mortal(newSVpv("encipherOnly",0)));
if (ASN1_BIT_STRING_get_bit(u,8)) XPUSHs(sv_2mortal(newSVpv("decipherOnly",0)));
}
void
P_X509_get_netscape_cert_type(cert)
X509 * cert
INIT:
ASN1_BIT_STRING * u;
PPCODE:
u = X509_get_ext_d2i(cert, NID_netscape_cert_type, NULL, NULL);
if (u) {
if (ASN1_BIT_STRING_get_bit(u,0)) XPUSHs(sv_2mortal(newSVpv("client",0)));
if (ASN1_BIT_STRING_get_bit(u,1)) XPUSHs(sv_2mortal(newSVpv("server",0)));
if (ASN1_BIT_STRING_get_bit(u,2)) XPUSHs(sv_2mortal(newSVpv("email",0)));
if (ASN1_BIT_STRING_get_bit(u,3)) XPUSHs(sv_2mortal(newSVpv("objsign",0)));
if (ASN1_BIT_STRING_get_bit(u,4)) XPUSHs(sv_2mortal(newSVpv("reserved",0)));
if (ASN1_BIT_STRING_get_bit(u,5)) XPUSHs(sv_2mortal(newSVpv("sslCA",0)));
if (ASN1_BIT_STRING_get_bit(u,6)) XPUSHs(sv_2mortal(newSVpv("emailCA",0)));
if (ASN1_BIT_STRING_get_bit(u,7)) XPUSHs(sv_2mortal(newSVpv("objCA",0)));
}
int
X509_get_ext_by_NID(x,nid,loc=-1)
X509* x
int nid
int loc
X509_EXTENSION *
X509_get_ext(x,loc)
X509* x
int loc
int
X509_EXTENSION_get_critical(X509_EXTENSION *ex)
ASN1_OCTET_STRING *
X509_EXTENSION_get_data(X509_EXTENSION *ne)
ASN1_OBJECT *
X509_EXTENSION_get_object(X509_EXTENSION *ex)
int
X509_get_ext_count(X509 *x)
int
X509_CRL_get_ext_count(X509_CRL *x)
int
X509_CRL_get_ext_by_NID(x,ni,loc=-1)
X509_CRL* x
int ni
int loc
X509_EXTENSION *
X509_CRL_get_ext(x,loc)
X509_CRL* x
int loc
void
X509V3_EXT_print(ext,flags=0,utf8_decode=0)
X509_EXTENSION * ext
unsigned long flags
int utf8_decode
PREINIT:
BIO * bp;
char * buf;
int i, n;
int indent=0;
CODE:
ST(0) = sv_newmortal(); /* undef to start with */
bp = BIO_new(BIO_s_mem());
if (bp) {
if(X509V3_EXT_print(bp,ext,flags,indent)) {
n = BIO_ctrl_pending(bp);
New(0, buf, n, char);
if (buf) {
i = BIO_read(bp,buf,n);
if (i>=0 && i<=n) {
sv_setpvn(ST(0), buf, i);
if (utf8_decode) sv_utf8_decode(ST(0));
}
Safefree(buf);
}
}
BIO_free(bp);
}
void *
X509V3_EXT_d2i(ext)
X509_EXTENSION *ext
int
X509_STORE_CTX_get_error(x509_store_ctx)
X509_STORE_CTX * x509_store_ctx
int
X509_STORE_CTX_get_error_depth(x509_store_ctx)
X509_STORE_CTX * x509_store_ctx
int
X509_STORE_CTX_set_ex_data(x509_store_ctx,idx,data)
X509_STORE_CTX * x509_store_ctx
int idx
void * data
void
X509_STORE_CTX_set_error(x509_store_ctx,s)
X509_STORE_CTX * x509_store_ctx
int s
void
X509_STORE_CTX_set_cert(x509_store_ctx,x)
X509_STORE_CTX * x509_store_ctx
X509 * x
int
X509_STORE_add_cert(ctx, x)
X509_STORE *ctx
X509 *x
int
X509_STORE_add_crl(ctx, x)
X509_STORE *ctx
X509_CRL *x
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
void
X509_STORE_set_flags(ctx, flags)
X509_STORE *ctx
long flags
void
X509_STORE_set_purpose(ctx, purpose)
X509_STORE *ctx
int purpose
void
X509_STORE_set_trust(ctx, trust)
X509_STORE *ctx
int trust
int
X509_STORE_set1_param(ctx, pm)
X509_STORE *ctx
X509_VERIFY_PARAM *pm
#endif
int
X509_load_cert_file(ctx, file, type)
X509_LOOKUP *ctx
char *file
int type
int
X509_load_crl_file(ctx, file, type)
X509_LOOKUP *ctx
char *file
int type
int
X509_load_cert_crl_file(ctx, file, type)
X509_LOOKUP *ctx
char *file
int type
const char *
X509_verify_cert_error_string(n)
long n
ASN1_INTEGER *
ASN1_INTEGER_new()
void
ASN1_INTEGER_free(ASN1_INTEGER *i)
int
ASN1_INTEGER_set(ASN1_INTEGER *i, long val)
long
ASN1_INTEGER_get(ASN1_INTEGER *a)
void
P_ASN1_INTEGER_set_hex(i,str)
ASN1_INTEGER * i
char * str
INIT:
BIGNUM *bn;
int rv = 1;
PPCODE:
bn = BN_new();
if (!BN_hex2bn(&bn, str)) XSRETURN_IV(0);
if (!BN_to_ASN1_INTEGER(bn, i)) rv = 0;
BN_free(bn);
XSRETURN_IV(rv);
void
P_ASN1_INTEGER_set_dec(i,str)
ASN1_INTEGER * i
char * str
INIT:
BIGNUM *bn;
int rv = 1;
PPCODE:
bn = BN_new();
if (!BN_dec2bn(&bn, str)) XSRETURN_IV(0);
if (!BN_to_ASN1_INTEGER(bn, i)) rv = 0;
BN_free(bn);
XSRETURN_IV(rv);
void
P_ASN1_INTEGER_get_hex(i)
ASN1_INTEGER * i
INIT:
BIGNUM *bn;
char *result;
PPCODE:
bn = BN_new();
if (!bn) XSRETURN_UNDEF;
ASN1_INTEGER_to_BN(i, bn);
result = BN_bn2hex(bn);
BN_free(bn);
if (!result) XSRETURN_UNDEF;
XPUSHs(sv_2mortal(newSVpv((const char*)result, strlen(result))));
OPENSSL_free(result);
void
P_ASN1_INTEGER_get_dec(i)
ASN1_INTEGER * i
INIT:
BIGNUM *bn;
char *result;
PPCODE:
bn = BN_new();
if (!bn) XSRETURN_UNDEF;
ASN1_INTEGER_to_BN(i, bn);
result = BN_bn2dec(bn);
BN_free(bn);
if (!result) XSRETURN_UNDEF;
XPUSHs(sv_2mortal(newSVpv((const char*)result, strlen(result))));
OPENSSL_free(result);
void
P_ASN1_STRING_get(s,utf8_decode=0)
ASN1_STRING * s
int utf8_decode
PREINIT:
SV * u8;
PPCODE:
u8 = newSVpv((const char*)ASN1_STRING_data(s), ASN1_STRING_length(s));
if (utf8_decode) sv_utf8_decode(u8);
XPUSHs(sv_2mortal(u8));
ASN1_TIME *
X509_get_notBefore(cert)
X509 * cert
ASN1_TIME *
X509_get_notAfter(cert)
X509 * cert
ASN1_TIME *
X509_gmtime_adj(s, adj)
ASN1_TIME * s
long adj
ASN1_TIME *
ASN1_TIME_set(s,t)
ASN1_TIME *s
time_t t
void
ASN1_TIME_free(s)
ASN1_TIME *s
time_t
ASN1_TIME_timet(s)
ASN1_TIME *s
ASN1_TIME *
ASN1_TIME_new()
void
P_ASN1_TIME_put2string(tm)
ASN1_TIME * tm
PREINIT:
BIO *bp=NULL;
int i=0;
char buffer[256];
ALIAS:
P_ASN1_UTCTIME_put2string = 1
CODE:
ST(0) = sv_newmortal(); /* undef retval to start with */
if (tm) {
bp = BIO_new(BIO_s_mem());
if (bp) {
ASN1_TIME_print(bp,tm);
i = BIO_read(bp,buffer,255);
buffer[i] = '\0';
if (i>0)
sv_setpvn(ST(0), buffer, i);
BIO_free(bp);
}
}
#if OPENSSL_VERSION_NUMBER >= 0x0090705f
#define REM15 "NOTE: requires 0.9.7e+"
void
P_ASN1_TIME_get_isotime(tm)
ASN1_TIME *tm
PREINIT:
ASN1_GENERALIZEDTIME *tmp = NULL;
char buf[256];
CODE:
buf[0] = '\0';
/* ASN1_TIME_to_generalizedtime is buggy on pre-0.9.7e */
ASN1_TIME_to_generalizedtime(tm,&tmp);
if (tmp) {
if (ASN1_GENERALIZEDTIME_check(tmp)) {
if (strlen((char*)tmp->data)>=14 && strlen((char*)tmp->data)<200) {
strcpy (buf,"yyyy-mm-ddThh:mm:ss");
strncpy(buf, (char*)tmp->data, 4);
strncpy(buf+5, (char*)tmp->data+4, 2);
strncpy(buf+8, (char*)tmp->data+6, 2);
strncpy(buf+11,(char*)tmp->data+8, 2);
strncpy(buf+14,(char*)tmp->data+10,2);
strncpy(buf+17,(char*)tmp->data+12,2);
if (strlen((char*)tmp->data)>14) strcat(buf+19,(char*)tmp->data+14);
}
}
ASN1_GENERALIZEDTIME_free(tmp);
}
ST(0) = sv_newmortal();
sv_setpv(ST(0), buf);
void
P_ASN1_TIME_set_isotime(tm,str)
ASN1_TIME *tm
const char *str
PREINIT:
ASN1_TIME t;
char buf[256];
int i,rv;
CODE:
if (!tm) XSRETURN_UNDEF;
/* we support only "2012-03-22T23:55:33" or "2012-03-22T23:55:33Z" or "2012-03-22T23:55:33<timezone>" */
if (strlen(str) < 19) XSRETURN_UNDEF;
for (i=0; i<4; i++) if ((str[i] > '9') || (str[i] < '0')) XSRETURN_UNDEF;
for (i=5; i<7; i++) if ((str[i] > '9') || (str[i] < '0')) XSRETURN_UNDEF;
for (i=8; i<10; i++) if ((str[i] > '9') || (str[i] < '0')) XSRETURN_UNDEF;
for (i=11; i<13; i++) if ((str[i] > '9') || (str[i] < '0')) XSRETURN_UNDEF;
for (i=14; i<16; i++) if ((str[i] > '9') || (str[i] < '0')) XSRETURN_UNDEF;
for (i=17; i<19; i++) if ((str[i] > '9') || (str[i] < '0')) XSRETURN_UNDEF;
strncpy(buf, str, 4);
strncpy(buf+4, str+5, 2);
strncpy(buf+6, str+8, 2);
strncpy(buf+8, str+11, 2);
strncpy(buf+10, str+14, 2);
strncpy(buf+12, str+17, 2);
buf[14] = '\0';
if (strlen(str)>19 && strlen(str)<200) strcat(buf,str+19);
/* WORKAROUND: ASN1_TIME_set_string() not available in 0.9.8 !!!*/
/* in 1.0.0 we would simply: rv = ASN1_TIME_set_string(tm,buf); */
t.length = strlen(buf);
t.data = (unsigned char *)buf;
t.flags = 0;
t.type = V_ASN1_UTCTIME;
if (!ASN1_TIME_check(&t)) {
t.type = V_ASN1_GENERALIZEDTIME;
if (!ASN1_TIME_check(&t)) XSRETURN_UNDEF;
}
tm->type = t.type;
tm->flags = t.flags;
if (!ASN1_STRING_set(tm,t.data,t.length)) XSRETURN_UNDEF;
rv = 1;
/* end of ASN1_TIME_set_string() reimplementation */
ST(0) = sv_newmortal();
sv_setiv(ST(0), rv); /* 1 = success, undef = failure */
#endif
int
EVP_PKEY_copy_parameters(to,from)
EVP_PKEY * to
EVP_PKEY * from
EVP_PKEY *
EVP_PKEY_new()
void
EVP_PKEY_free(EVP_PKEY *pkey)
int
EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *key)
int
EVP_PKEY_bits(EVP_PKEY *pkey)
int
EVP_PKEY_size(EVP_PKEY *pkey)
#if OPENSSL_VERSION_NUMBER >= 0x1000000fL
int
EVP_PKEY_id(const EVP_PKEY *pkey)
#endif
void
PEM_get_string_X509(x509)
X509 * x509
PREINIT:
BIO *bp;
int i, n;
char *buf;
CODE:
ST(0) = sv_newmortal(); /* undef to start with */
bp = BIO_new(BIO_s_mem());
if (bp && x509) {
PEM_write_bio_X509(bp,x509);
n = BIO_ctrl_pending(bp);
New(0, buf, n, char);
if (buf) {
i = BIO_read(bp,buf,n);
if (i>=0 && i<=n) sv_setpvn(ST(0), buf, i);
Safefree(buf);
}
BIO_free(bp);
}
void
PEM_get_string_X509_REQ(x509_req)
X509_REQ * x509_req
PREINIT:
BIO *bp;
int i, n;
char *buf;
CODE:
ST(0) = sv_newmortal(); /* undef to start with */
bp = BIO_new(BIO_s_mem());
if (bp && x509_req) {
PEM_write_bio_X509_REQ(bp,x509_req);
n = BIO_ctrl_pending(bp);
New(0, buf, n, char);
if (buf) {
i = BIO_read(bp,buf,n);
if (i>=0 && i<=n) sv_setpvn(ST(0), buf, i);
Safefree(buf);
}
BIO_free(bp);
}
void
PEM_get_string_X509_CRL(x509_crl)
X509_CRL * x509_crl
PREINIT:
BIO *bp;
int i, n;
char *buf;
CODE:
ST(0) = sv_newmortal(); /* undef to start with */
bp = BIO_new(BIO_s_mem());
if (bp && x509_crl) {
PEM_write_bio_X509_CRL(bp,x509_crl);
n = BIO_ctrl_pending(bp);
New(0, buf, n, char);
if (buf) {
i = BIO_read(bp,buf,n);
if (i>=0 && i<=n) sv_setpvn(ST(0), buf, i);
Safefree(buf);
}
BIO_free(bp);
}
void
PEM_get_string_PrivateKey(pk,passwd=NULL,enc_alg=NULL)
EVP_PKEY * pk
char * passwd
const EVP_CIPHER * enc_alg
PREINIT:
BIO *bp;
int i, n;
char *buf;
size_t passwd_len = 0;
pem_password_cb * cb = NULL;
void * u = NULL;
CODE:
ST(0) = sv_newmortal(); /* undef to start with */
bp = BIO_new(BIO_s_mem());
if (bp && pk) {
if (passwd) passwd_len = strlen(passwd);
if (passwd_len>0) {
/* encrypted key */
if (!enc_alg)
PEM_write_bio_PrivateKey(bp,pk,EVP_des_cbc(),(unsigned char *)passwd,passwd_len,cb,u);
else
PEM_write_bio_PrivateKey(bp,pk,enc_alg,(unsigned char *)passwd,passwd_len,cb,u);
}
else {
/* unencrypted key */
PEM_write_bio_PrivateKey(bp,pk,NULL,(unsigned char *)passwd,passwd_len,cb,u);
}
n = BIO_ctrl_pending(bp);
New(0, buf, n, char);
if (buf) {
i = BIO_read(bp,buf,n);
if (i>=0 && i<=n) sv_setpvn(ST(0), buf, i);
Safefree(buf);
}
BIO_free(bp);
}
int
CTX_use_PKCS12_file(ctx, file, password=NULL)
SSL_CTX *ctx
char *file
char *password
PREINIT:
PKCS12 *p12;
EVP_PKEY *private_key;
X509 *certificate;
FILE *fp;
CODE:
RETVAL = 0;
if ((fp = fopen (file, "rb"))) {
#if OPENSSL_VERSION_NUMBER >= 0x0090700fL
OPENSSL_add_all_algorithms_noconf();
#else
OpenSSL_add_all_algorithms();
#endif
if ((p12 = d2i_PKCS12_fp(fp, NULL))) {
if (PKCS12_parse(p12, password, &private_key, &certificate, NULL)) {
if (private_key) {
if (SSL_CTX_use_PrivateKey(ctx, private_key)) RETVAL = 1;
EVP_PKEY_free(private_key);
}
if (certificate) {
if (SSL_CTX_use_certificate(ctx, certificate)) RETVAL = 1;
X509_free(certificate);
}
}
PKCS12_free(p12);
}
if (!RETVAL) ERR_print_errors_fp(stderr);
fclose(fp);
}
OUTPUT:
RETVAL
void
P_PKCS12_load_file(file, load_chain=0, password=NULL)
char *file
int load_chain
char *password
PREINIT:
PKCS12 *p12;
EVP_PKEY *private_key = NULL;
X509 *certificate = NULL;
STACK_OF(X509) *cachain = NULL;
X509 *x;
FILE *fp;
int i, result;
PPCODE:
if ((fp = fopen (file, "rb"))) {
#if OPENSSL_VERSION_NUMBER >= 0x0090700fL
OPENSSL_add_all_algorithms_noconf();
#else
OpenSSL_add_all_algorithms();
#endif
if ((p12 = d2i_PKCS12_fp(fp, NULL))) {
if(load_chain)
result= PKCS12_parse(p12, password, &private_key, &certificate, &cachain);
else
result= PKCS12_parse(p12, password, &private_key, &certificate, NULL);
if (result) {
if (private_key)
XPUSHs(sv_2mortal(newSViv(PTR2IV(private_key))));
else
XPUSHs(sv_2mortal(newSVpv(NULL,0))); /* undef */
if (certificate)
XPUSHs(sv_2mortal(newSViv(PTR2IV(certificate))));
else
XPUSHs(sv_2mortal(newSVpv(NULL,0))); /* undef */
if (cachain) {
for (i=0; i<sk_X509_num(cachain); i++) {
x = sk_X509_value(cachain, i);
XPUSHs(sv_2mortal(newSViv(PTR2IV(x))));
}
sk_X509_free(cachain);
}
}
PKCS12_free(p12);
}
fclose(fp);
}
#ifndef OPENSSL_NO_MD2
void
MD2(data)
PREINIT:
STRLEN len;
unsigned char md[MD2_DIGEST_LENGTH];
unsigned char * ret;
INPUT:
unsigned char* data = (unsigned char *) SvPV( ST(0), len);
CODE:
ret = MD2(data,len,md);
if (ret!=NULL) {
XSRETURN_PVN((char *) md, MD2_DIGEST_LENGTH);
} else {
XSRETURN_UNDEF;
}
#endif
void
MD4(data)
PREINIT:
STRLEN len;
unsigned char md[MD4_DIGEST_LENGTH];
INPUT:
unsigned char* data = (unsigned char *) SvPV( ST(0), len );
CODE:
if (MD4(data,len,md)) {
XSRETURN_PVN((char *) md, MD4_DIGEST_LENGTH);
} else {
XSRETURN_UNDEF;
}
void
MD5(data)
PREINIT:
STRLEN len;
unsigned char md[MD5_DIGEST_LENGTH];
INPUT:
unsigned char * data = (unsigned char *) SvPV( ST(0), len);
CODE:
if (MD5(data,len,md)) {
XSRETURN_PVN((char *) md, MD5_DIGEST_LENGTH);
} else {
XSRETURN_UNDEF;
}
#if OPENSSL_VERSION_NUMBER >= 0x00905000L
void
RIPEMD160(data)
PREINIT:
STRLEN len;
unsigned char md[RIPEMD160_DIGEST_LENGTH];
INPUT:
unsigned char * data = (unsigned char *) SvPV( ST(0), len);
CODE:
if (RIPEMD160(data,len,md)) {
XSRETURN_PVN((char *) md, RIPEMD160_DIGEST_LENGTH);
} else {
XSRETURN_UNDEF;
}
#endif
#if !defined(OPENSSL_NO_SHA)
void
SHA1(data)
PREINIT:
STRLEN len;
unsigned char md[SHA_DIGEST_LENGTH];
INPUT:
unsigned char * data = (unsigned char *) SvPV( ST(0), len);
CODE:
if (SHA1(data,len,md)) {
XSRETURN_PVN((char *) md, SHA_DIGEST_LENGTH);
} else {
XSRETURN_UNDEF;
}
#endif
#if !defined(OPENSSL_NO_SHA256) && OPENSSL_VERSION_NUMBER >= 0x0090800fL
void
SHA256(data)
PREINIT:
STRLEN len;
unsigned char md[SHA256_DIGEST_LENGTH];
INPUT:
unsigned char * data = (unsigned char *) SvPV( ST(0), len);
CODE:
if (SHA256(data,len,md)) {
XSRETURN_PVN((char *) md, SHA256_DIGEST_LENGTH);
} else {
XSRETURN_UNDEF;
}
#endif
#if !defined(OPENSSL_NO_SHA512) && OPENSSL_VERSION_NUMBER >= 0x0090800fL
void
SHA512(data)
PREINIT:
STRLEN len;
unsigned char md[SHA512_DIGEST_LENGTH];
INPUT:
unsigned char * data = (unsigned char *) SvPV( ST(0), len);
CODE:
if (SHA512(data,len,md)) {
XSRETURN_PVN((char *) md, SHA512_DIGEST_LENGTH);
} else {
XSRETURN_UNDEF;
}
#endif
#ifndef OPENSSL_NO_SSL2
#if OPENSSL_VERSION_NUMBER < 0x10000000L
const SSL_METHOD *
SSLv2_method()
#endif
#endif
const SSL_METHOD *
SSLv3_method()
const SSL_METHOD *
TLSv1_method()
#ifdef SSL_TXT_TLSV1_1
const SSL_METHOD *
TLSv1_1_method()
#endif
#ifdef SSL_TXT_TLSV1_2
const SSL_METHOD *
TLSv1_2_method()
#endif
#if OPENSSL_VERSION_NUMBER < 0x10000000L
int
SSL_set_ssl_method(ssl, method)
SSL * ssl
SSL_METHOD * method
#else
int
SSL_set_ssl_method(ssl, method)
SSL * ssl
const SSL_METHOD * method
#endif
const SSL_METHOD *
SSL_get_ssl_method(ssl)
SSL * ssl
#define REM_AUTOMATICALLY_GENERATED_1_09
BIO *
BIO_new_buffer_ssl_connect(ctx)
SSL_CTX * ctx
BIO *
BIO_new_file(filename,mode)
char * filename
char * mode
BIO *
BIO_new_ssl(ctx,client)
SSL_CTX * ctx
int client
BIO *
BIO_new_ssl_connect(ctx)
SSL_CTX * ctx
BIO *
BIO_new(type)
BIO_METHOD * type;
int
BIO_free(bio)
BIO * bio;
void
BIO_read(s,max=32768)
BIO * s
int max
PREINIT:
char *buf = NULL;
int got;
CODE:
New(0, buf, max, char);
ST(0) = sv_newmortal(); /* Undefined to start with */
if ((got = BIO_read(s, buf, max)) >= 0)
sv_setpvn( ST(0), buf, got);
Safefree(buf);
int
BIO_write(s,buf)
BIO * s
PREINIT:
STRLEN len;
INPUT:
char * buf = SvPV( ST(1), len);
CODE:
RETVAL = BIO_write (s, buf, (int)len);
OUTPUT:
RETVAL
int
BIO_eof(s)
BIO * s
int
BIO_pending(s)
BIO * s
int
BIO_wpending(s)
BIO * s
int
BIO_ssl_copy_session_id(to,from)
BIO * to
BIO * from
void
BIO_ssl_shutdown(ssl_bio)
BIO * ssl_bio
int
SSL_add_client_CA(ssl,x)
SSL * ssl
X509 * x
const char *
SSL_alert_desc_string(value)
int value
const char *
SSL_alert_desc_string_long(value)
int value
const char *
SSL_alert_type_string(value)
int value
const char *
SSL_alert_type_string_long(value)
int value
long
SSL_callback_ctrl(ssl,i,fp)
SSL * ssl
int i
callback_no_ret * fp
int
SSL_check_private_key(ctx)
SSL * ctx
#if OPENSSL_VERSION_NUMBER < 0x009080dfL
#define REM8 "NOTE: before 0.9.8m"
char *
SSL_CIPHER_description(cipher,buf,size)
SSL_CIPHER * cipher
char * buf
int size
#else
char *
SSL_CIPHER_description(cipher,buf,size)
const SSL_CIPHER * cipher
char * buf
int size
#endif
#if OPENSSL_VERSION_NUMBER < 0x0090707fL
#define REM9 "NOTE: before 0.9.7g"
const char *
SSL_CIPHER_get_name(SSL_CIPHER *c)
int
SSL_CIPHER_get_bits(c,alg_bits=NULL)
SSL_CIPHER * c
int * alg_bits
#else
const char *
SSL_CIPHER_get_name(const SSL_CIPHER *c)
int
SSL_CIPHER_get_bits(c,alg_bits=NULL)
const SSL_CIPHER * c
int * alg_bits
#endif
int
SSL_COMP_add_compression_method(id,cm)
int id
COMP_METHOD * cm
int
SSL_CTX_add_client_CA(ctx,x)
SSL_CTX * ctx
X509 * x
long
SSL_CTX_callback_ctrl(ctx,i,fp)
SSL_CTX * ctx