/* @(#)ssl.c 1.1 VMS-99/01/30 python wrapper for SSLeay https */ #include "Python.h" #if defined(WITH_THREAD) && !defined(HAVE_GETHOSTBYNAME_R) &&\ !defined(MS_WINDOWS) #include "thread.h" #endif #include #ifndef MS_WINDOWS #include #else #include #endif #if defined(PYOS_OS2) #define INCL_DOS #define INCL_DOSERRORS #define INCL_NOPMAPI #include #endif #include "ssl.h" #include "err.h" /* some hacks to choose between K&R or ANSI style function definitions. For NT to build this as an extension module (ie, DLL) it must be compiled by the C++ compiler, as it takes the address of a static data item exported from the main Python DLL. */ #ifdef MS_WINDOWS #define FORCE_ANSI_FUNC_DEFS #endif #if defined(PYOS_OS2) #define FORCE_ANSI_FUNC_DEFS #endif #ifdef FORCE_ANSI_FUNC_DEFS #define BUILD_FUNC_DEF_1( fnname, arg1type, arg1name ) \ fnname( arg1type arg1name ) #define BUILD_FUNC_DEF_2( fnname, arg1type, arg1name, arg2type, arg2name ) \ fnname( arg1type arg1name, arg2type arg2name ) #else /* !FORCE_ANSI_FN_DEFS */ #define BUILD_FUNC_DEF_1( fnname, arg1type, arg1name ) \ fnname( arg1name ) \ arg1type arg1name; #define BUILD_FUNC_DEF_2( fnname, arg1type, arg1name, arg2type, arg2name ) \ fnname( arg1name, arg2name ) \ arg1type arg1name; \ arg2type arg2name; #endif /* !FORCE_ANSI_FN_DEFS */ /* Global variable holding the exception type for errors detected by this module (but not argument type or memory errors, etc.). */ static PyObject *PySslError; typedef struct { PyObject_HEAD int sock_fd; PyObject *x_attr; /* attributes dictionary */ SSL_CTX *ctx; SSL *ssl; X509 *server_cert; BIO *sbio; char server[256]; char issuer[256]; } PySslObject; staticforward PyTypeObject SSL_Type; #define PySslObject_Check(v) ((v)->ob_type == &SSL_Type) /* * raise an error according to errno, return NULL */ static PyObject * PySsl_errno () { #ifdef MS_WINDOWS if (WSAGetLastError()) { PyObject *v = Py_BuildValue("(is)",WSAGetLastError(),"winsock error"); if (v) { PyErr_SetObject(PySslError,v); Py_DECREF(v); } return NULL; } #endif return PyErr_SetFromErrno(PySslError); } /* * format SSl error string */ static int BUILD_FUNC_DEF_2 (PySsl_err_str, unsigned long, e, char *, buf) { unsigned long l = ERR_GET_LIB(e); unsigned long f = ERR_GET_FUNC(e); unsigned long r = ERR_GET_REASON(e); char* ls = (char*)ERR_lib_error_string(e); char* fs = (char*)ERR_func_error_string(e); char* rs = (char*)ERR_reason_error_string(e); char* bp = buf + 2; /* skip two initial blanks */ (void)strcpy(buf," none:"); /* initialize buffer */ bp += (ls) ? sprintf(bp,"%s:",ls) : ((l) ? sprintf(bp,"lib %lu:",l) : 0); bp += (fs) ? sprintf(bp,"%s ",fs) : ((f) ? sprintf(bp,"func %lu:",f) : 0); bp += (rs) ? sprintf(bp,"%s:",rs) : ((r) ? sprintf(bp,"reason(%lu):",r) : 0); *bp-- = 0; /* suppress last divider (:) */ return (bp - buf); } /* * report SSL core errors */ static PySslObject * PySsl_errors () { #define PY_SSL_ERR_MAX 256 unsigned long e; char buf[2 * PY_SSL_ERR_MAX]; char *bf = buf; while (((bf - buf) < PY_SSL_ERR_MAX) && (e = ERR_get_error())) bf += PySsl_err_str(e,bf); { PyObject *v = Py_BuildValue("(sss)", "ssl","core",buf+2); if (v != NULL) { PyErr_SetObject(PySslError,v); Py_DECREF(v); } } return (NULL); } /* * report SSL application layer errors */ static PySslObject * BUILD_FUNC_DEF_2 (PySsl_app_errors, SSL *, s, int, ret) { int err = SSL_get_error(s,ret); char *str; switch (err) { case SSL_ERROR_SSL: return (PySsl_errors()); case SSL_ERROR_SYSCALL: return ((PySslObject *)PySsl_errno()); case SSL_ERROR_ZERO_RETURN: str = "End of data"; break; case SSL_ERROR_WANT_READ: str = "Want read"; break; case SSL_ERROR_WANT_WRITE: str = "Want write"; break; case SSL_ERROR_WANT_X509_LOOKUP: str = "Want x509 lookup"; break; case SSL_ERROR_WANT_CONNECT: str = "Want connect"; break; default: str = "Unknown"; break; } { PyObject *v = Py_BuildValue("(sis)", "ssl",err, str); if (v != NULL) { PyErr_SetObject(PySslError,v); Py_DECREF(v); } } return (NULL); } /* ssl.read(len) method */ static PyObject * BUILD_FUNC_DEF_2 (PySslObj_read, PySslObject *, self, PyObject *, args) { int len, n; PyObject *buf; if (!PyArg_ParseTuple(args,"i",&len)) return (NULL); if (!(buf = PyString_FromStringAndSize((char *)0,len))) return (NULL); Py_BEGIN_ALLOW_THREADS n = SSL_read(self->ssl,PyString_AsString(buf),len); Py_END_ALLOW_THREADS switch (SSL_get_error(self->ssl,n)) { case SSL_ERROR_NONE: /* good return value */ break; case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_SYSCALL: if (!n) /* fix SSL_ERROR_SYCSALL errno=0 case */ break; /* fall thru here */ default: Py_DECREF(buf); (void)PySsl_app_errors(self->ssl,n); return (NULL); } if ((n != len) && (_PyString_Resize(&buf,n) < 0)) return (NULL); return (buf); } /* ssl.write(data,len) method */ static PyObject * BUILD_FUNC_DEF_2 (PySslObj_write, PySslObject *, self, PyObject *, args) { char *buf; int len, n; if (!PyArg_ParseTuple(args, "si", &buf, &len)) return NULL; /* Note: flags are ignored */ Py_BEGIN_ALLOW_THREADS n = SSL_write(self->ssl,buf,len); Py_END_ALLOW_THREADS if (n < 0) return (PySsl_errno()); return (PyInt_FromLong((long)n)); } /* ssl.server() method */ static PyObject * BUILD_FUNC_DEF_2 (PySslObj_server, PySslObject *, self, PyObject *, args) { if (!PyArg_NoArgs(args)) return (NULL); return (PyString_FromString(self->server)); } /* ssl.issuer() method */ static PyObject * BUILD_FUNC_DEF_2 (PySslObj_issuer, PySslObject *, self, PyObject *, args) { if (!PyArg_NoArgs(args)) return (NULL); return (PyString_FromString(self->issuer)); } /* SSL object methods */ static PyMethodDef PySslObj_methods[] = { {"read", (PyCFunction)PySslObj_read,1}, {"write", (PyCFunction)PySslObj_write,1}, {"server", (PyCFunction)PySslObj_server}, {"issuer", (PyCFunction)PySslObj_issuer}, { NULL, NULL} }; static void BUILD_FUNC_DEF_1 (PySsl_dealloc, PySslObject *, self) { if (self->server_cert) /* possible not to have one? */ X509_free(self->server_cert); SSL_CTX_free(self->ctx); SSL_free(self->ssl); Py_XDECREF(self->x_attr); PyMem_DEL(self); } static PyObject * BUILD_FUNC_DEF_2 (PySsl_getattr, PySslObject *, self, char *, name) { return (Py_FindMethod(PySslObj_methods,(PyObject *)self,name)); } staticforward PyTypeObject SSL_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, /*ob_size*/ "SSL", /*tp_name*/ sizeof(PySslObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)PySsl_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ (getattrfunc)PySsl_getattr, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ }; /* * C function called for new object initialization * Note: SSL protocol version 2, 3, or 2+3 set at compile time */ static PySslObject * BUILD_FUNC_DEF_1 (newPySslObject, int, sock_fd) { PySslObject *self; SSL_METHOD *meth; int ret; #if 0 meth=SSLv3_client_method(); meth=SSLv23_client_method(); #endif meth=SSLv2_client_method(); if (!(self = PyObject_NEW(PySslObject,&SSL_Type))) /* create new object */ return (NULL); (void)memset(self->server,0,sizeof(self->server)); (void)memset(self->issuer,0,sizeof(self->issuer)); self->x_attr = PyDict_New(); if (!(self->ctx = SSL_CTX_new(meth))) { /* set up context */ PyMem_DEL(self); return (PySsl_errors()); } #if 0 /* Note: set this for v23, Netscape server */ SSL_CTX_set_options(self->ctx,SSL_OP_ALL); #endif self->ssl = SSL_new(self->ctx); /* new ssl struct */ if (!(ret = SSL_set_fd(self->ssl,sock_fd))) { /* set the socket for SSL */ PyMem_DEL(self); return (PySsl_app_errors(self->ssl,ret)); } SSL_CTX_set_verify(self->ctx,SSL_VERIFY_NONE,NULL); /* set verify lvl */ SSL_set_connect_state(self->ssl); if ((ret = SSL_connect(self->ssl)) < 0) { /* negotiate SSL connection */ PyMem_DEL(self); return (PySsl_app_errors(self->ssl,ret)); } self->ssl->debug = 1; if ((self->server_cert = SSL_get_peer_certificate(self->ssl))) { X509_NAME_oneline(X509_get_subject_name(self->server_cert), self->server,sizeof(self->server)); X509_NAME_oneline(X509_get_issuer_name(self->server_cert), self->issuer, sizeof(self->issuer)); } self->x_attr = NULL; self->sock_fd = sock_fd; return (self); } /* * Python function called for new object initialization */ static PyObject * BUILD_FUNC_DEF_2 (PySsl_ssl_new, PyObject *, self, PyObject *, args) { int sock_fd; if (!PyArg_ParseTuple(args, "i", &sock_fd)) return (NULL); return ((PyObject *)newPySslObject(sock_fd)); } /* List of functions exported by this module. */ static PyMethodDef PySsl_methods[] = { {"ssl", (PyCFunction)PySsl_ssl_new, 1}, {NULL, NULL} /* sentinel */ }; /* * Initialize this module, called when the first 'import ssl' is done */ void initssl () { PyObject *m, *d; m = Py_InitModule("ssl", PySsl_methods); d = PyModule_GetDict(m); SSL_load_error_strings(); SSLeay_add_ssl_algorithms(); /* *** Python 1.5 *** if (!(PySssl_Error = PyErr_NewException("ssl.error",NULL,NULL))) return; */ if (!(PySslError = PyString_FromString("ssl.error")) || PyDict_SetItemString(d,"error",PySslError)) Py_FatalError("can't define ssl.error"); if (PyDict_SetItemString(d,"SSLType",(PyObject *)&SSL_Type)) return; }