Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
a4c2a5c9
Commit
a4c2a5c9
authored
May 05, 2010
by
Antoine Pitrou
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Untabify Modules/_ssl.c
parent
91165c0b
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
1346 additions
and
1346 deletions
+1346
-1346
Modules/_ssl.c
Modules/_ssl.c
+1346
-1346
No files found.
Modules/_ssl.c
View file @
a4c2a5c9
...
...
@@ -19,14 +19,14 @@
#ifdef WITH_THREAD
#include "pythread.h"
#define PySSL_BEGIN_ALLOW_THREADS { \
PyThreadState *_save = NULL; \
if (_ssl_locks_count>0) {_save = PyEval_SaveThread();}
#define PySSL_BLOCK_THREADS
if (_ssl_locks_count>0){PyEval_RestoreThread(_save)};
#define PySSL_UNBLOCK_THREADS
if (_ssl_locks_count>0){_save = PyEval_SaveThread()};
#define PySSL_END_ALLOW_THREADS
if (_ssl_locks_count>0){PyEval_RestoreThread(_save);} \
}
PyThreadState *_save = NULL; \
if (_ssl_locks_count>0) {_save = PyEval_SaveThread();}
#define PySSL_BLOCK_THREADS
if (_ssl_locks_count>0){PyEval_RestoreThread(_save)};
#define PySSL_UNBLOCK_THREADS
if (_ssl_locks_count>0){_save = PyEval_SaveThread()};
#define PySSL_END_ALLOW_THREADS
if (_ssl_locks_count>0){PyEval_RestoreThread(_save);} \
}
#else
/* no WITH_THREAD */
#else
/* no WITH_THREAD */
#define PySSL_BEGIN_ALLOW_THREADS
#define PySSL_BLOCK_THREADS
...
...
@@ -36,36 +36,36 @@
#endif
enum
py_ssl_error
{
/* these mirror ssl.h */
PY_SSL_ERROR_NONE
,
PY_SSL_ERROR_SSL
,
PY_SSL_ERROR_WANT_READ
,
PY_SSL_ERROR_WANT_WRITE
,
PY_SSL_ERROR_WANT_X509_LOOKUP
,
PY_SSL_ERROR_SYSCALL
,
/* look at error stack/return value/errno */
PY_SSL_ERROR_ZERO_RETURN
,
PY_SSL_ERROR_WANT_CONNECT
,
/* start of non ssl.h errorcodes */
PY_SSL_ERROR_EOF
,
/* special case of SSL_ERROR_SYSCALL */
PY_SSL_ERROR_INVALID_ERROR_CODE
/* these mirror ssl.h */
PY_SSL_ERROR_NONE
,
PY_SSL_ERROR_SSL
,
PY_SSL_ERROR_WANT_READ
,
PY_SSL_ERROR_WANT_WRITE
,
PY_SSL_ERROR_WANT_X509_LOOKUP
,
PY_SSL_ERROR_SYSCALL
,
/* look at error stack/return value/errno */
PY_SSL_ERROR_ZERO_RETURN
,
PY_SSL_ERROR_WANT_CONNECT
,
/* start of non ssl.h errorcodes */
PY_SSL_ERROR_EOF
,
/* special case of SSL_ERROR_SYSCALL */
PY_SSL_ERROR_INVALID_ERROR_CODE
};
enum
py_ssl_server_or_client
{
PY_SSL_CLIENT
,
PY_SSL_SERVER
PY_SSL_CLIENT
,
PY_SSL_SERVER
};
enum
py_ssl_cert_requirements
{
PY_SSL_CERT_NONE
,
PY_SSL_CERT_OPTIONAL
,
PY_SSL_CERT_REQUIRED
PY_SSL_CERT_NONE
,
PY_SSL_CERT_OPTIONAL
,
PY_SSL_CERT_REQUIRED
};
enum
py_ssl_version
{
PY_SSL_VERSION_SSL2
,
PY_SSL_VERSION_SSL3
,
PY_SSL_VERSION_SSL23
,
PY_SSL_VERSION_TLS1
PY_SSL_VERSION_SSL2
,
PY_SSL_VERSION_SSL3
,
PY_SSL_VERSION_SSL23
,
PY_SSL_VERSION_TLS1
};
/* Include symbols from _socket module */
...
...
@@ -111,14 +111,14 @@ static unsigned int _ssl_locks_count = 0;
#endif
typedef
struct
{
PyObject_HEAD
PySocketSockObject
*
Socket
;
/* Socket on which we're layered */
SSL_CTX
*
ctx
;
SSL
*
ssl
;
X509
*
peer_cert
;
char
server
[
X509_NAME_MAXLEN
];
char
issuer
[
X509_NAME_MAXLEN
];
int
shutdown_seen_zero
;
PyObject_HEAD
PySocketSockObject
*
Socket
;
/* Socket on which we're layered */
SSL_CTX
*
ctx
;
SSL
*
ssl
;
X509
*
peer_cert
;
char
server
[
X509_NAME_MAXLEN
];
char
issuer
[
X509_NAME_MAXLEN
];
int
shutdown_seen_zero
;
}
PySSLObject
;
...
...
@@ -126,19 +126,19 @@ static PyTypeObject PySSL_Type;
static
PyObject
*
PySSL_SSLwrite
(
PySSLObject
*
self
,
PyObject
*
args
);
static
PyObject
*
PySSL_SSLread
(
PySSLObject
*
self
,
PyObject
*
args
);
static
int
check_socket_and_wait_for_timeout
(
PySocketSockObject
*
s
,
int
writing
);
int
writing
);
static
PyObject
*
PySSL_peercert
(
PySSLObject
*
self
,
PyObject
*
args
);
static
PyObject
*
PySSL_cipher
(
PySSLObject
*
self
);
#define PySSLObject_Check(v)
(Py_TYPE(v) == &PySSL_Type)
#define PySSLObject_Check(v)
(Py_TYPE(v) == &PySSL_Type)
typedef
enum
{
SOCKET_IS_NONBLOCKING
,
SOCKET_IS_BLOCKING
,
SOCKET_HAS_TIMED_OUT
,
SOCKET_HAS_BEEN_CLOSED
,
SOCKET_TOO_LARGE_FOR_SELECT
,
SOCKET_OPERATION_OK
SOCKET_IS_NONBLOCKING
,
SOCKET_IS_BLOCKING
,
SOCKET_HAS_TIMED_OUT
,
SOCKET_HAS_BEEN_CLOSED
,
SOCKET_TOO_LARGE_FOR_SELECT
,
SOCKET_OPERATION_OK
}
timeout_state
;
/* Wrap error strings with filename and line # */
...
...
@@ -155,294 +155,294 @@ typedef enum {
static
PyObject
*
PySSL_SetError
(
PySSLObject
*
obj
,
int
ret
,
char
*
filename
,
int
lineno
)
{
PyObject
*
v
;
char
buf
[
2048
];
char
*
errstr
;
int
err
;
enum
py_ssl_error
p
=
PY_SSL_ERROR_NONE
;
assert
(
ret
<=
0
);
if
(
obj
->
ssl
!=
NULL
)
{
err
=
SSL_get_error
(
obj
->
ssl
,
ret
);
switch
(
err
)
{
case
SSL_ERROR_ZERO_RETURN
:
errstr
=
"TLS/SSL connection has been closed"
;
p
=
PY_SSL_ERROR_ZERO_RETURN
;
break
;
case
SSL_ERROR_WANT_READ
:
errstr
=
"The operation did not complete (read)"
;
p
=
PY_SSL_ERROR_WANT_READ
;
break
;
case
SSL_ERROR_WANT_WRITE
:
p
=
PY_SSL_ERROR_WANT_WRITE
;
errstr
=
"The operation did not complete (write)"
;
break
;
case
SSL_ERROR_WANT_X509_LOOKUP
:
p
=
PY_SSL_ERROR_WANT_X509_LOOKUP
;
errstr
=
"The operation did not complete (X509 lookup)"
;
break
;
case
SSL_ERROR_WANT_CONNECT
:
p
=
PY_SSL_ERROR_WANT_CONNECT
;
errstr
=
"The operation did not complete (connect)"
;
break
;
case
SSL_ERROR_SYSCALL
:
{
unsigned
long
e
=
ERR_get_error
();
if
(
e
==
0
)
{
if
(
ret
==
0
||
!
obj
->
Socket
)
{
p
=
PY_SSL_ERROR_EOF
;
errstr
=
"EOF occurred in violation of protocol"
;
}
else
if
(
ret
==
-
1
)
{
/* underlying BIO reported an I/O error */
return
obj
->
Socket
->
errorhandler
();
}
else
{
/* possible? */
p
=
PY_SSL_ERROR_SYSCALL
;
errstr
=
"Some I/O error occurred"
;
}
}
else
{
p
=
PY_SSL_ERROR_SYSCALL
;
/* XXX Protected by global interpreter lock */
errstr
=
ERR_error_string
(
e
,
NULL
);
}
break
;
}
case
SSL_ERROR_SSL
:
{
unsigned
long
e
=
ERR_get_error
();
p
=
PY_SSL_ERROR_SSL
;
if
(
e
!=
0
)
/* XXX Protected by global interpreter lock */
errstr
=
ERR_error_string
(
e
,
NULL
);
else
{
/* possible? */
errstr
=
"A failure in the SSL library occurred"
;
}
break
;
}
default:
p
=
PY_SSL_ERROR_INVALID_ERROR_CODE
;
errstr
=
"Invalid error code"
;
}
}
else
{
errstr
=
ERR_error_string
(
ERR_peek_last_error
(),
NULL
);
}
PyOS_snprintf
(
buf
,
sizeof
(
buf
),
"_ssl.c:%d: %s"
,
lineno
,
errstr
);
v
=
Py_BuildValue
(
"(is)"
,
p
,
buf
);
if
(
v
!=
NULL
)
{
PyErr_SetObject
(
PySSLErrorObject
,
v
);
Py_DECREF
(
v
);
}
return
NULL
;
PyObject
*
v
;
char
buf
[
2048
];
char
*
errstr
;
int
err
;
enum
py_ssl_error
p
=
PY_SSL_ERROR_NONE
;
assert
(
ret
<=
0
);
if
(
obj
->
ssl
!=
NULL
)
{
err
=
SSL_get_error
(
obj
->
ssl
,
ret
);
switch
(
err
)
{
case
SSL_ERROR_ZERO_RETURN
:
errstr
=
"TLS/SSL connection has been closed"
;
p
=
PY_SSL_ERROR_ZERO_RETURN
;
break
;
case
SSL_ERROR_WANT_READ
:
errstr
=
"The operation did not complete (read)"
;
p
=
PY_SSL_ERROR_WANT_READ
;
break
;
case
SSL_ERROR_WANT_WRITE
:
p
=
PY_SSL_ERROR_WANT_WRITE
;
errstr
=
"The operation did not complete (write)"
;
break
;
case
SSL_ERROR_WANT_X509_LOOKUP
:
p
=
PY_SSL_ERROR_WANT_X509_LOOKUP
;
errstr
=
"The operation did not complete (X509 lookup)"
;
break
;
case
SSL_ERROR_WANT_CONNECT
:
p
=
PY_SSL_ERROR_WANT_CONNECT
;
errstr
=
"The operation did not complete (connect)"
;
break
;
case
SSL_ERROR_SYSCALL
:
{
unsigned
long
e
=
ERR_get_error
();
if
(
e
==
0
)
{
if
(
ret
==
0
||
!
obj
->
Socket
)
{
p
=
PY_SSL_ERROR_EOF
;
errstr
=
"EOF occurred in violation of protocol"
;
}
else
if
(
ret
==
-
1
)
{
/* underlying BIO reported an I/O error */
return
obj
->
Socket
->
errorhandler
();
}
else
{
/* possible? */
p
=
PY_SSL_ERROR_SYSCALL
;
errstr
=
"Some I/O error occurred"
;
}
}
else
{
p
=
PY_SSL_ERROR_SYSCALL
;
/* XXX Protected by global interpreter lock */
errstr
=
ERR_error_string
(
e
,
NULL
);
}
break
;
}
case
SSL_ERROR_SSL
:
{
unsigned
long
e
=
ERR_get_error
();
p
=
PY_SSL_ERROR_SSL
;
if
(
e
!=
0
)
/* XXX Protected by global interpreter lock */
errstr
=
ERR_error_string
(
e
,
NULL
);
else
{
/* possible? */
errstr
=
"A failure in the SSL library occurred"
;
}
break
;
}
default:
p
=
PY_SSL_ERROR_INVALID_ERROR_CODE
;
errstr
=
"Invalid error code"
;
}
}
else
{
errstr
=
ERR_error_string
(
ERR_peek_last_error
(),
NULL
);
}
PyOS_snprintf
(
buf
,
sizeof
(
buf
),
"_ssl.c:%d: %s"
,
lineno
,
errstr
);
v
=
Py_BuildValue
(
"(is)"
,
p
,
buf
);
if
(
v
!=
NULL
)
{
PyErr_SetObject
(
PySSLErrorObject
,
v
);
Py_DECREF
(
v
);
}
return
NULL
;
}
static
PyObject
*
_setSSLError
(
char
*
errstr
,
int
errcode
,
char
*
filename
,
int
lineno
)
{
char
buf
[
2048
];
PyObject
*
v
;
if
(
errstr
==
NULL
)
{
errcode
=
ERR_peek_last_error
();
errstr
=
ERR_error_string
(
errcode
,
NULL
);
}
PyOS_snprintf
(
buf
,
sizeof
(
buf
),
"_ssl.c:%d: %s"
,
lineno
,
errstr
);
v
=
Py_BuildValue
(
"(is)"
,
errcode
,
buf
);
if
(
v
!=
NULL
)
{
PyErr_SetObject
(
PySSLErrorObject
,
v
);
Py_DECREF
(
v
);
}
return
NULL
;
char
buf
[
2048
];
PyObject
*
v
;
if
(
errstr
==
NULL
)
{
errcode
=
ERR_peek_last_error
();
errstr
=
ERR_error_string
(
errcode
,
NULL
);
}
PyOS_snprintf
(
buf
,
sizeof
(
buf
),
"_ssl.c:%d: %s"
,
lineno
,
errstr
);
v
=
Py_BuildValue
(
"(is)"
,
errcode
,
buf
);
if
(
v
!=
NULL
)
{
PyErr_SetObject
(
PySSLErrorObject
,
v
);
Py_DECREF
(
v
);
}
return
NULL
;
}
static
PySSLObject
*
newPySSLObject
(
PySocketSockObject
*
Sock
,
char
*
key_file
,
char
*
cert_file
,
enum
py_ssl_server_or_client
socket_type
,
enum
py_ssl_cert_requirements
certreq
,
enum
py_ssl_version
proto_version
,
char
*
cacerts_file
,
char
*
ciphers
)
enum
py_ssl_server_or_client
socket_type
,
enum
py_ssl_cert_requirements
certreq
,
enum
py_ssl_version
proto_version
,
char
*
cacerts_file
,
char
*
ciphers
)
{
PySSLObject
*
self
;
char
*
errstr
=
NULL
;
int
ret
;
int
verification_mode
;
self
=
PyObject_New
(
PySSLObject
,
&
PySSL_Type
);
/* Create new object */
if
(
self
==
NULL
)
return
NULL
;
memset
(
self
->
server
,
'\0'
,
sizeof
(
char
)
*
X509_NAME_MAXLEN
);
memset
(
self
->
issuer
,
'\0'
,
sizeof
(
char
)
*
X509_NAME_MAXLEN
);
self
->
peer_cert
=
NULL
;
self
->
ssl
=
NULL
;
self
->
ctx
=
NULL
;
self
->
Socket
=
NULL
;
/* Make sure the SSL error state is initialized */
(
void
)
ERR_get_state
();
ERR_clear_error
();
if
((
key_file
&&
!
cert_file
)
||
(
!
key_file
&&
cert_file
))
{
errstr
=
ERRSTR
(
"Both the key & certificate files "
"must be specified"
);
goto
fail
;
}
if
((
socket_type
==
PY_SSL_SERVER
)
&&
((
key_file
==
NULL
)
||
(
cert_file
==
NULL
)))
{
errstr
=
ERRSTR
(
"Both the key & certificate files "
"must be specified for server-side operation"
);
goto
fail
;
}
PySSL_BEGIN_ALLOW_THREADS
if
(
proto_version
==
PY_SSL_VERSION_TLS1
)
self
->
ctx
=
SSL_CTX_new
(
TLSv1_method
());
/* Set up context */
else
if
(
proto_version
==
PY_SSL_VERSION_SSL3
)
self
->
ctx
=
SSL_CTX_new
(
SSLv3_method
());
/* Set up context */
else
if
(
proto_version
==
PY_SSL_VERSION_SSL2
)
self
->
ctx
=
SSL_CTX_new
(
SSLv2_method
());
/* Set up context */
else
if
(
proto_version
==
PY_SSL_VERSION_SSL23
)
self
->
ctx
=
SSL_CTX_new
(
SSLv23_method
());
/* Set up context */
PySSL_END_ALLOW_THREADS
if
(
self
->
ctx
==
NULL
)
{
errstr
=
ERRSTR
(
"Invalid SSL protocol variant specified."
);
goto
fail
;
}
if
(
ciphers
!=
NULL
)
{
ret
=
SSL_CTX_set_cipher_list
(
self
->
ctx
,
ciphers
);
if
(
ret
==
0
)
{
errstr
=
ERRSTR
(
"No cipher can be selected."
);
goto
fail
;
}
}
if
(
certreq
!=
PY_SSL_CERT_NONE
)
{
if
(
cacerts_file
==
NULL
)
{
errstr
=
ERRSTR
(
"No root certificates specified for "
"verification of other-side certificates."
);
goto
fail
;
}
else
{
PySSL_BEGIN_ALLOW_THREADS
ret
=
SSL_CTX_load_verify_locations
(
self
->
ctx
,
cacerts_file
,
NULL
);
PySSL_END_ALLOW_THREADS
if
(
ret
!=
1
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
goto
fail
;
}
}
}
if
(
key_file
)
{
PySSL_BEGIN_ALLOW_THREADS
ret
=
SSL_CTX_use_PrivateKey_file
(
self
->
ctx
,
key_file
,
SSL_FILETYPE_PEM
);
PySSL_END_ALLOW_THREADS
if
(
ret
!=
1
)
{
_setSSLError
(
NULL
,
ret
,
__FILE__
,
__LINE__
);
goto
fail
;
}
PySSL_BEGIN_ALLOW_THREADS
ret
=
SSL_CTX_use_certificate_chain_file
(
self
->
ctx
,
cert_file
);
PySSL_END_ALLOW_THREADS
if
(
ret
!=
1
)
{
/*
fprintf(stderr, "ret is %d, errcode is %lu, %lu, with file \"%s\"\n",
ret, ERR_peek_error(), ERR_peek_last_error(), cert_file);
*/
if
(
ERR_peek_last_error
()
!=
0
)
{
_setSSLError
(
NULL
,
ret
,
__FILE__
,
__LINE__
);
goto
fail
;
}
}
}
/* ssl compatibility */
SSL_CTX_set_options
(
self
->
ctx
,
SSL_OP_ALL
);
verification_mode
=
SSL_VERIFY_NONE
;
if
(
certreq
==
PY_SSL_CERT_OPTIONAL
)
verification_mode
=
SSL_VERIFY_PEER
;
else
if
(
certreq
==
PY_SSL_CERT_REQUIRED
)
verification_mode
=
(
SSL_VERIFY_PEER
|
SSL_VERIFY_FAIL_IF_NO_PEER_CERT
);
SSL_CTX_set_verify
(
self
->
ctx
,
verification_mode
,
NULL
);
/* set verify lvl */
PySSL_BEGIN_ALLOW_THREADS
self
->
ssl
=
SSL_new
(
self
->
ctx
);
/* New ssl struct */
PySSL_END_ALLOW_THREADS
SSL_set_fd
(
self
->
ssl
,
Sock
->
sock_fd
);
/* Set the socket for SSL */
PySSLObject
*
self
;
char
*
errstr
=
NULL
;
int
ret
;
int
verification_mode
;
self
=
PyObject_New
(
PySSLObject
,
&
PySSL_Type
);
/* Create new object */
if
(
self
==
NULL
)
return
NULL
;
memset
(
self
->
server
,
'\0'
,
sizeof
(
char
)
*
X509_NAME_MAXLEN
);
memset
(
self
->
issuer
,
'\0'
,
sizeof
(
char
)
*
X509_NAME_MAXLEN
);
self
->
peer_cert
=
NULL
;
self
->
ssl
=
NULL
;
self
->
ctx
=
NULL
;
self
->
Socket
=
NULL
;
/* Make sure the SSL error state is initialized */
(
void
)
ERR_get_state
();
ERR_clear_error
();
if
((
key_file
&&
!
cert_file
)
||
(
!
key_file
&&
cert_file
))
{
errstr
=
ERRSTR
(
"Both the key & certificate files "
"must be specified"
);
goto
fail
;
}
if
((
socket_type
==
PY_SSL_SERVER
)
&&
((
key_file
==
NULL
)
||
(
cert_file
==
NULL
)))
{
errstr
=
ERRSTR
(
"Both the key & certificate files "
"must be specified for server-side operation"
);
goto
fail
;
}
PySSL_BEGIN_ALLOW_THREADS
if
(
proto_version
==
PY_SSL_VERSION_TLS1
)
self
->
ctx
=
SSL_CTX_new
(
TLSv1_method
());
/* Set up context */
else
if
(
proto_version
==
PY_SSL_VERSION_SSL3
)
self
->
ctx
=
SSL_CTX_new
(
SSLv3_method
());
/* Set up context */
else
if
(
proto_version
==
PY_SSL_VERSION_SSL2
)
self
->
ctx
=
SSL_CTX_new
(
SSLv2_method
());
/* Set up context */
else
if
(
proto_version
==
PY_SSL_VERSION_SSL23
)
self
->
ctx
=
SSL_CTX_new
(
SSLv23_method
());
/* Set up context */
PySSL_END_ALLOW_THREADS
if
(
self
->
ctx
==
NULL
)
{
errstr
=
ERRSTR
(
"Invalid SSL protocol variant specified."
);
goto
fail
;
}
if
(
ciphers
!=
NULL
)
{
ret
=
SSL_CTX_set_cipher_list
(
self
->
ctx
,
ciphers
);
if
(
ret
==
0
)
{
errstr
=
ERRSTR
(
"No cipher can be selected."
);
goto
fail
;
}
}
if
(
certreq
!=
PY_SSL_CERT_NONE
)
{
if
(
cacerts_file
==
NULL
)
{
errstr
=
ERRSTR
(
"No root certificates specified for "
"verification of other-side certificates."
);
goto
fail
;
}
else
{
PySSL_BEGIN_ALLOW_THREADS
ret
=
SSL_CTX_load_verify_locations
(
self
->
ctx
,
cacerts_file
,
NULL
);
PySSL_END_ALLOW_THREADS
if
(
ret
!=
1
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
goto
fail
;
}
}
}
if
(
key_file
)
{
PySSL_BEGIN_ALLOW_THREADS
ret
=
SSL_CTX_use_PrivateKey_file
(
self
->
ctx
,
key_file
,
SSL_FILETYPE_PEM
);
PySSL_END_ALLOW_THREADS
if
(
ret
!=
1
)
{
_setSSLError
(
NULL
,
ret
,
__FILE__
,
__LINE__
);
goto
fail
;
}
PySSL_BEGIN_ALLOW_THREADS
ret
=
SSL_CTX_use_certificate_chain_file
(
self
->
ctx
,
cert_file
);
PySSL_END_ALLOW_THREADS
if
(
ret
!=
1
)
{
/*
fprintf(stderr, "ret is %d, errcode is %lu, %lu, with file \"%s\"\n",
ret, ERR_peek_error(), ERR_peek_last_error(), cert_file);
*/
if
(
ERR_peek_last_error
()
!=
0
)
{
_setSSLError
(
NULL
,
ret
,
__FILE__
,
__LINE__
);
goto
fail
;
}
}
}
/* ssl compatibility */
SSL_CTX_set_options
(
self
->
ctx
,
SSL_OP_ALL
);
verification_mode
=
SSL_VERIFY_NONE
;
if
(
certreq
==
PY_SSL_CERT_OPTIONAL
)
verification_mode
=
SSL_VERIFY_PEER
;
else
if
(
certreq
==
PY_SSL_CERT_REQUIRED
)
verification_mode
=
(
SSL_VERIFY_PEER
|
SSL_VERIFY_FAIL_IF_NO_PEER_CERT
);
SSL_CTX_set_verify
(
self
->
ctx
,
verification_mode
,
NULL
);
/* set verify lvl */
PySSL_BEGIN_ALLOW_THREADS
self
->
ssl
=
SSL_new
(
self
->
ctx
);
/* New ssl struct */
PySSL_END_ALLOW_THREADS
SSL_set_fd
(
self
->
ssl
,
Sock
->
sock_fd
);
/* Set the socket for SSL */
#ifdef SSL_MODE_AUTO_RETRY
SSL_set_mode
(
self
->
ssl
,
SSL_MODE_AUTO_RETRY
);
SSL_set_mode
(
self
->
ssl
,
SSL_MODE_AUTO_RETRY
);
#endif
/* If the socket is in non-blocking mode or timeout mode, set the BIO
* to non-blocking mode (blocking is the default)
*/
if
(
Sock
->
sock_timeout
>=
0
.
0
)
{
/* Set both the read and write BIO's to non-blocking mode */
BIO_set_nbio
(
SSL_get_rbio
(
self
->
ssl
),
1
);
BIO_set_nbio
(
SSL_get_wbio
(
self
->
ssl
),
1
);
}
PySSL_BEGIN_ALLOW_THREADS
if
(
socket_type
==
PY_SSL_CLIENT
)
SSL_set_connect_state
(
self
->
ssl
);
else
SSL_set_accept_state
(
self
->
ssl
);
PySSL_END_ALLOW_THREADS
self
->
Socket
=
Sock
;
Py_INCREF
(
self
->
Socket
);
return
self
;
/* If the socket is in non-blocking mode or timeout mode, set the BIO
* to non-blocking mode (blocking is the default)
*/
if
(
Sock
->
sock_timeout
>=
0
.
0
)
{
/* Set both the read and write BIO's to non-blocking mode */
BIO_set_nbio
(
SSL_get_rbio
(
self
->
ssl
),
1
);
BIO_set_nbio
(
SSL_get_wbio
(
self
->
ssl
),
1
);
}
PySSL_BEGIN_ALLOW_THREADS
if
(
socket_type
==
PY_SSL_CLIENT
)
SSL_set_connect_state
(
self
->
ssl
);
else
SSL_set_accept_state
(
self
->
ssl
);
PySSL_END_ALLOW_THREADS
self
->
Socket
=
Sock
;
Py_INCREF
(
self
->
Socket
);
return
self
;
fail:
if
(
errstr
)
PyErr_SetString
(
PySSLErrorObject
,
errstr
);
Py_DECREF
(
self
);
return
NULL
;
if
(
errstr
)
PyErr_SetString
(
PySSLErrorObject
,
errstr
);
Py_DECREF
(
self
);
return
NULL
;
}
static
PyObject
*
PySSL_sslwrap
(
PyObject
*
self
,
PyObject
*
args
)
{
PySocketSockObject
*
Sock
;
int
server_side
=
0
;
int
verification_mode
=
PY_SSL_CERT_NONE
;
int
protocol
=
PY_SSL_VERSION_SSL23
;
char
*
key_file
=
NULL
;
char
*
cert_file
=
NULL
;
char
*
cacerts_file
=
NULL
;
char
*
ciphers
=
NULL
;
if
(
!
PyArg_ParseTuple
(
args
,
"O!i|zziizz:sslwrap"
,
PySocketModule
.
Sock_Type
,
&
Sock
,
&
server_side
,
&
key_file
,
&
cert_file
,
&
verification_mode
,
&
protocol
,
&
cacerts_file
,
&
ciphers
))
return
NULL
;
/*
fprintf(stderr,
"server_side is %d, keyfile %p, certfile %p, verify_mode %d, "
"protocol %d, certs %p\n",
server_side, key_file, cert_file, verification_mode,
protocol, cacerts_file);
*/
return
(
PyObject
*
)
newPySSLObject
(
Sock
,
key_file
,
cert_file
,
server_side
,
verification_mode
,
protocol
,
cacerts_file
,
ciphers
);
PySocketSockObject
*
Sock
;
int
server_side
=
0
;
int
verification_mode
=
PY_SSL_CERT_NONE
;
int
protocol
=
PY_SSL_VERSION_SSL23
;
char
*
key_file
=
NULL
;
char
*
cert_file
=
NULL
;
char
*
cacerts_file
=
NULL
;
char
*
ciphers
=
NULL
;
if
(
!
PyArg_ParseTuple
(
args
,
"O!i|zziizz:sslwrap"
,
PySocketModule
.
Sock_Type
,
&
Sock
,
&
server_side
,
&
key_file
,
&
cert_file
,
&
verification_mode
,
&
protocol
,
&
cacerts_file
,
&
ciphers
))
return
NULL
;
/*
fprintf(stderr,
"server_side is %d, keyfile %p, certfile %p, verify_mode %d, "
"protocol %d, certs %p\n",
server_side, key_file, cert_file, verification_mode,
protocol, cacerts_file);
*/
return
(
PyObject
*
)
newPySSLObject
(
Sock
,
key_file
,
cert_file
,
server_side
,
verification_mode
,
protocol
,
cacerts_file
,
ciphers
);
}
PyDoc_STRVAR
(
ssl_doc
,
...
...
@@ -453,577 +453,577 @@ PyDoc_STRVAR(ssl_doc,
static
PyObject
*
PySSL_SSLdo_handshake
(
PySSLObject
*
self
)
{
int
ret
;
int
err
;
int
sockstate
,
nonblocking
;
/* just in case the blocking state of the socket has been changed */
nonblocking
=
(
self
->
Socket
->
sock_timeout
>=
0
.
0
);
BIO_set_nbio
(
SSL_get_rbio
(
self
->
ssl
),
nonblocking
);
BIO_set_nbio
(
SSL_get_wbio
(
self
->
ssl
),
nonblocking
);
/* Actually negotiate SSL connection */
/* XXX If SSL_do_handshake() returns 0, it's also a failure. */
do
{
PySSL_BEGIN_ALLOW_THREADS
ret
=
SSL_do_handshake
(
self
->
ssl
);
err
=
SSL_get_error
(
self
->
ssl
,
ret
);
PySSL_END_ALLOW_THREADS
if
(
PyErr_CheckSignals
())
{
return
NULL
;
}
if
(
err
==
SSL_ERROR_WANT_READ
)
{
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
0
);
}
else
if
(
err
==
SSL_ERROR_WANT_WRITE
)
{
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
1
);
}
else
{
sockstate
=
SOCKET_OPERATION_OK
;
}
if
(
sockstate
==
SOCKET_HAS_TIMED_OUT
)
{
PyErr_SetString
(
PySSLErrorObject
,
ERRSTR
(
"The handshake operation timed out"
));
return
NULL
;
}
else
if
(
sockstate
==
SOCKET_HAS_BEEN_CLOSED
)
{
PyErr_SetString
(
PySSLErrorObject
,
ERRSTR
(
"Underlying socket has been closed."
));
return
NULL
;
}
else
if
(
sockstate
==
SOCKET_TOO_LARGE_FOR_SELECT
)
{
PyErr_SetString
(
PySSLErrorObject
,
ERRSTR
(
"Underlying socket too large for select()."
));
return
NULL
;
}
else
if
(
sockstate
==
SOCKET_IS_NONBLOCKING
)
{
break
;
}
}
while
(
err
==
SSL_ERROR_WANT_READ
||
err
==
SSL_ERROR_WANT_WRITE
);
if
(
ret
<
1
)
return
PySSL_SetError
(
self
,
ret
,
__FILE__
,
__LINE__
);
self
->
ssl
->
debug
=
1
;
if
(
self
->
peer_cert
)
X509_free
(
self
->
peer_cert
);
PySSL_BEGIN_ALLOW_THREADS
if
((
self
->
peer_cert
=
SSL_get_peer_certificate
(
self
->
ssl
)))
{
X509_NAME_oneline
(
X509_get_subject_name
(
self
->
peer_cert
),
self
->
server
,
X509_NAME_MAXLEN
);
X509_NAME_oneline
(
X509_get_issuer_name
(
self
->
peer_cert
),
self
->
issuer
,
X509_NAME_MAXLEN
);
}
PySSL_END_ALLOW_THREADS
Py_INCREF
(
Py_None
);
return
Py_None
;
int
ret
;
int
err
;
int
sockstate
,
nonblocking
;
/* just in case the blocking state of the socket has been changed */
nonblocking
=
(
self
->
Socket
->
sock_timeout
>=
0
.
0
);
BIO_set_nbio
(
SSL_get_rbio
(
self
->
ssl
),
nonblocking
);
BIO_set_nbio
(
SSL_get_wbio
(
self
->
ssl
),
nonblocking
);
/* Actually negotiate SSL connection */
/* XXX If SSL_do_handshake() returns 0, it's also a failure. */
do
{
PySSL_BEGIN_ALLOW_THREADS
ret
=
SSL_do_handshake
(
self
->
ssl
);
err
=
SSL_get_error
(
self
->
ssl
,
ret
);
PySSL_END_ALLOW_THREADS
if
(
PyErr_CheckSignals
())
{
return
NULL
;
}
if
(
err
==
SSL_ERROR_WANT_READ
)
{
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
0
);
}
else
if
(
err
==
SSL_ERROR_WANT_WRITE
)
{
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
1
);
}
else
{
sockstate
=
SOCKET_OPERATION_OK
;
}
if
(
sockstate
==
SOCKET_HAS_TIMED_OUT
)
{
PyErr_SetString
(
PySSLErrorObject
,
ERRSTR
(
"The handshake operation timed out"
));
return
NULL
;
}
else
if
(
sockstate
==
SOCKET_HAS_BEEN_CLOSED
)
{
PyErr_SetString
(
PySSLErrorObject
,
ERRSTR
(
"Underlying socket has been closed."
));
return
NULL
;
}
else
if
(
sockstate
==
SOCKET_TOO_LARGE_FOR_SELECT
)
{
PyErr_SetString
(
PySSLErrorObject
,
ERRSTR
(
"Underlying socket too large for select()."
));
return
NULL
;
}
else
if
(
sockstate
==
SOCKET_IS_NONBLOCKING
)
{
break
;
}
}
while
(
err
==
SSL_ERROR_WANT_READ
||
err
==
SSL_ERROR_WANT_WRITE
);
if
(
ret
<
1
)
return
PySSL_SetError
(
self
,
ret
,
__FILE__
,
__LINE__
);
self
->
ssl
->
debug
=
1
;
if
(
self
->
peer_cert
)
X509_free
(
self
->
peer_cert
);
PySSL_BEGIN_ALLOW_THREADS
if
((
self
->
peer_cert
=
SSL_get_peer_certificate
(
self
->
ssl
)))
{
X509_NAME_oneline
(
X509_get_subject_name
(
self
->
peer_cert
),
self
->
server
,
X509_NAME_MAXLEN
);
X509_NAME_oneline
(
X509_get_issuer_name
(
self
->
peer_cert
),
self
->
issuer
,
X509_NAME_MAXLEN
);
}
PySSL_END_ALLOW_THREADS
Py_INCREF
(
Py_None
);
return
Py_None
;
}
static
PyObject
*
PySSL_server
(
PySSLObject
*
self
)
{
return
PyString_FromString
(
self
->
server
);
return
PyString_FromString
(
self
->
server
);
}
static
PyObject
*
PySSL_issuer
(
PySSLObject
*
self
)
{
return
PyString_FromString
(
self
->
issuer
);
return
PyString_FromString
(
self
->
issuer
);
}
static
PyObject
*
_create_tuple_for_attribute
(
ASN1_OBJECT
*
name
,
ASN1_STRING
*
value
)
{
char
namebuf
[
X509_NAME_MAXLEN
];
int
buflen
;
PyObject
*
name_obj
;
PyObject
*
value_obj
;
PyObject
*
attr
;
unsigned
char
*
valuebuf
=
NULL
;
buflen
=
OBJ_obj2txt
(
namebuf
,
sizeof
(
namebuf
),
name
,
0
);
if
(
buflen
<
0
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
goto
fail
;
}
name_obj
=
PyString_FromStringAndSize
(
namebuf
,
buflen
);
if
(
name_obj
==
NULL
)
goto
fail
;
buflen
=
ASN1_STRING_to_UTF8
(
&
valuebuf
,
value
);
if
(
buflen
<
0
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
Py_DECREF
(
name_obj
);
goto
fail
;
}
value_obj
=
PyUnicode_DecodeUTF8
((
char
*
)
valuebuf
,
buflen
,
"strict"
);
OPENSSL_free
(
valuebuf
);
if
(
value_obj
==
NULL
)
{
Py_DECREF
(
name_obj
);
goto
fail
;
}
attr
=
PyTuple_New
(
2
);
if
(
attr
==
NULL
)
{
Py_DECREF
(
name_obj
);
Py_DECREF
(
value_obj
);
goto
fail
;
}
PyTuple_SET_ITEM
(
attr
,
0
,
name_obj
);
PyTuple_SET_ITEM
(
attr
,
1
,
value_obj
);
return
attr
;
char
namebuf
[
X509_NAME_MAXLEN
];
int
buflen
;
PyObject
*
name_obj
;
PyObject
*
value_obj
;
PyObject
*
attr
;
unsigned
char
*
valuebuf
=
NULL
;
buflen
=
OBJ_obj2txt
(
namebuf
,
sizeof
(
namebuf
),
name
,
0
);
if
(
buflen
<
0
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
goto
fail
;
}
name_obj
=
PyString_FromStringAndSize
(
namebuf
,
buflen
);
if
(
name_obj
==
NULL
)
goto
fail
;
buflen
=
ASN1_STRING_to_UTF8
(
&
valuebuf
,
value
);
if
(
buflen
<
0
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
Py_DECREF
(
name_obj
);
goto
fail
;
}
value_obj
=
PyUnicode_DecodeUTF8
((
char
*
)
valuebuf
,
buflen
,
"strict"
);
OPENSSL_free
(
valuebuf
);
if
(
value_obj
==
NULL
)
{
Py_DECREF
(
name_obj
);
goto
fail
;
}
attr
=
PyTuple_New
(
2
);
if
(
attr
==
NULL
)
{
Py_DECREF
(
name_obj
);
Py_DECREF
(
value_obj
);
goto
fail
;
}
PyTuple_SET_ITEM
(
attr
,
0
,
name_obj
);
PyTuple_SET_ITEM
(
attr
,
1
,
value_obj
);
return
attr
;
fail:
return
NULL
;
return
NULL
;
}
static
PyObject
*
_create_tuple_for_X509_NAME
(
X509_NAME
*
xname
)
{
PyObject
*
dn
=
NULL
;
/* tuple which represents the "distinguished name" */
PyObject
*
rdn
=
NULL
;
/* tuple to hold a "relative distinguished name" */
PyObject
*
rdnt
;
PyObject
*
attr
=
NULL
;
/* tuple to hold an attribute */
int
entry_count
=
X509_NAME_entry_count
(
xname
);
X509_NAME_ENTRY
*
entry
;
ASN1_OBJECT
*
name
;
ASN1_STRING
*
value
;
int
index_counter
;
int
rdn_level
=
-
1
;
int
retcode
;
dn
=
PyList_New
(
0
);
if
(
dn
==
NULL
)
return
NULL
;
/* now create another tuple to hold the top-level RDN */
rdn
=
PyList_New
(
0
);
if
(
rdn
==
NULL
)
goto
fail0
;
for
(
index_counter
=
0
;
index_counter
<
entry_count
;
index_counter
++
)
{
entry
=
X509_NAME_get_entry
(
xname
,
index_counter
);
/* check to see if we've gotten to a new RDN */
if
(
rdn_level
>=
0
)
{
if
(
rdn_level
!=
entry
->
set
)
{
/* yes, new RDN */
/* add old RDN to DN */
rdnt
=
PyList_AsTuple
(
rdn
);
Py_DECREF
(
rdn
);
if
(
rdnt
==
NULL
)
goto
fail0
;
retcode
=
PyList_Append
(
dn
,
rdnt
);
Py_DECREF
(
rdnt
);
if
(
retcode
<
0
)
goto
fail0
;
/* create new RDN */
rdn
=
PyList_New
(
0
);
if
(
rdn
==
NULL
)
goto
fail0
;
}
}
rdn_level
=
entry
->
set
;
/* now add this attribute to the current RDN */
name
=
X509_NAME_ENTRY_get_object
(
entry
);
value
=
X509_NAME_ENTRY_get_data
(
entry
);
attr
=
_create_tuple_for_attribute
(
name
,
value
);
/*
fprintf(stderr, "RDN level %d, attribute %s: %s\n",
entry->set,
PyString_AS_STRING(PyTuple_GET_ITEM(attr, 0)),
PyString_AS_STRING(PyTuple_GET_ITEM(attr, 1)));
*/
if
(
attr
==
NULL
)
goto
fail1
;
retcode
=
PyList_Append
(
rdn
,
attr
);
Py_DECREF
(
attr
);
if
(
retcode
<
0
)
goto
fail1
;
}
/* now, there's typically a dangling RDN */
if
((
rdn
!=
NULL
)
&&
(
PyList_Size
(
rdn
)
>
0
))
{
rdnt
=
PyList_AsTuple
(
rdn
);
Py_DECREF
(
rdn
);
if
(
rdnt
==
NULL
)
goto
fail0
;
retcode
=
PyList_Append
(
dn
,
rdnt
);
Py_DECREF
(
rdnt
);
if
(
retcode
<
0
)
goto
fail0
;
}
/* convert list to tuple */
rdnt
=
PyList_AsTuple
(
dn
);
Py_DECREF
(
dn
);
if
(
rdnt
==
NULL
)
return
NULL
;
return
rdnt
;
PyObject
*
dn
=
NULL
;
/* tuple which represents the "distinguished name" */
PyObject
*
rdn
=
NULL
;
/* tuple to hold a "relative distinguished name" */
PyObject
*
rdnt
;
PyObject
*
attr
=
NULL
;
/* tuple to hold an attribute */
int
entry_count
=
X509_NAME_entry_count
(
xname
);
X509_NAME_ENTRY
*
entry
;
ASN1_OBJECT
*
name
;
ASN1_STRING
*
value
;
int
index_counter
;
int
rdn_level
=
-
1
;
int
retcode
;
dn
=
PyList_New
(
0
);
if
(
dn
==
NULL
)
return
NULL
;
/* now create another tuple to hold the top-level RDN */
rdn
=
PyList_New
(
0
);
if
(
rdn
==
NULL
)
goto
fail0
;
for
(
index_counter
=
0
;
index_counter
<
entry_count
;
index_counter
++
)
{
entry
=
X509_NAME_get_entry
(
xname
,
index_counter
);
/* check to see if we've gotten to a new RDN */
if
(
rdn_level
>=
0
)
{
if
(
rdn_level
!=
entry
->
set
)
{
/* yes, new RDN */
/* add old RDN to DN */
rdnt
=
PyList_AsTuple
(
rdn
);
Py_DECREF
(
rdn
);
if
(
rdnt
==
NULL
)
goto
fail0
;
retcode
=
PyList_Append
(
dn
,
rdnt
);
Py_DECREF
(
rdnt
);
if
(
retcode
<
0
)
goto
fail0
;
/* create new RDN */
rdn
=
PyList_New
(
0
);
if
(
rdn
==
NULL
)
goto
fail0
;
}
}
rdn_level
=
entry
->
set
;
/* now add this attribute to the current RDN */
name
=
X509_NAME_ENTRY_get_object
(
entry
);
value
=
X509_NAME_ENTRY_get_data
(
entry
);
attr
=
_create_tuple_for_attribute
(
name
,
value
);
/*
fprintf(stderr, "RDN level %d, attribute %s: %s\n",
entry->set,
PyString_AS_STRING(PyTuple_GET_ITEM(attr, 0)),
PyString_AS_STRING(PyTuple_GET_ITEM(attr, 1)));
*/
if
(
attr
==
NULL
)
goto
fail1
;
retcode
=
PyList_Append
(
rdn
,
attr
);
Py_DECREF
(
attr
);
if
(
retcode
<
0
)
goto
fail1
;
}
/* now, there's typically a dangling RDN */
if
((
rdn
!=
NULL
)
&&
(
PyList_Size
(
rdn
)
>
0
))
{
rdnt
=
PyList_AsTuple
(
rdn
);
Py_DECREF
(
rdn
);
if
(
rdnt
==
NULL
)
goto
fail0
;
retcode
=
PyList_Append
(
dn
,
rdnt
);
Py_DECREF
(
rdnt
);
if
(
retcode
<
0
)
goto
fail0
;
}
/* convert list to tuple */
rdnt
=
PyList_AsTuple
(
dn
);
Py_DECREF
(
dn
);
if
(
rdnt
==
NULL
)
return
NULL
;
return
rdnt
;
fail1:
Py_XDECREF
(
rdn
);
Py_XDECREF
(
rdn
);
fail0:
Py_XDECREF
(
dn
);
return
NULL
;
Py_XDECREF
(
dn
);
return
NULL
;
}
static
PyObject
*
_get_peer_alt_names
(
X509
*
certificate
)
{
/* this code follows the procedure outlined in
OpenSSL's crypto/x509v3/v3_prn.c:X509v3_EXT_print()
function to extract the STACK_OF(GENERAL_NAME),
then iterates through the stack to add the
names. */
int
i
,
j
;
PyObject
*
peer_alt_names
=
Py_None
;
PyObject
*
v
,
*
t
;
X509_EXTENSION
*
ext
=
NULL
;
GENERAL_NAMES
*
names
=
NULL
;
GENERAL_NAME
*
name
;
X509V3_EXT_METHOD
*
method
;
BIO
*
biobuf
=
NULL
;
char
buf
[
2048
];
char
*
vptr
;
int
len
;
/* Issue #2973: ASN1_item_d2i() API changed in OpenSSL 0.9.6m */
/* this code follows the procedure outlined in
OpenSSL's crypto/x509v3/v3_prn.c:X509v3_EXT_print()
function to extract the STACK_OF(GENERAL_NAME),
then iterates through the stack to add the
names. */
int
i
,
j
;
PyObject
*
peer_alt_names
=
Py_None
;
PyObject
*
v
,
*
t
;
X509_EXTENSION
*
ext
=
NULL
;
GENERAL_NAMES
*
names
=
NULL
;
GENERAL_NAME
*
name
;
X509V3_EXT_METHOD
*
method
;
BIO
*
biobuf
=
NULL
;
char
buf
[
2048
];
char
*
vptr
;
int
len
;
/* Issue #2973: ASN1_item_d2i() API changed in OpenSSL 0.9.6m */
#if OPENSSL_VERSION_NUMBER >= 0x009060dfL
const
unsigned
char
*
p
;
const
unsigned
char
*
p
;
#else
unsigned
char
*
p
;
unsigned
char
*
p
;
#endif
if
(
certificate
==
NULL
)
return
peer_alt_names
;
/* get a memory buffer */
biobuf
=
BIO_new
(
BIO_s_mem
());
i
=
0
;
while
((
i
=
X509_get_ext_by_NID
(
certificate
,
NID_subject_alt_name
,
i
))
>=
0
)
{
if
(
peer_alt_names
==
Py_None
)
{
peer_alt_names
=
PyList_New
(
0
);
if
(
peer_alt_names
==
NULL
)
goto
fail
;
}
/* now decode the altName */
ext
=
X509_get_ext
(
certificate
,
i
);
if
(
!
(
method
=
X509V3_EXT_get
(
ext
)))
{
PyErr_SetString
(
PySSLErrorObject
,
ERRSTR
(
"No method for internalizing subjectAltName!"
));
goto
fail
;
}
p
=
ext
->
value
->
data
;
if
(
method
->
it
)
names
=
(
GENERAL_NAMES
*
)
(
ASN1_item_d2i
(
NULL
,
&
p
,
ext
->
value
->
length
,
ASN1_ITEM_ptr
(
method
->
it
)));
else
names
=
(
GENERAL_NAMES
*
)
(
method
->
d2i
(
NULL
,
&
p
,
ext
->
value
->
length
));
for
(
j
=
0
;
j
<
sk_GENERAL_NAME_num
(
names
);
j
++
)
{
/* get a rendering of each name in the set of names */
name
=
sk_GENERAL_NAME_value
(
names
,
j
);
if
(
name
->
type
==
GEN_DIRNAME
)
{
/* we special-case DirName as a tuple of tuples of attributes */
t
=
PyTuple_New
(
2
);
if
(
t
==
NULL
)
{
goto
fail
;
}
v
=
PyString_FromString
(
"DirName"
);
if
(
v
==
NULL
)
{
Py_DECREF
(
t
);
goto
fail
;
}
PyTuple_SET_ITEM
(
t
,
0
,
v
);
v
=
_create_tuple_for_X509_NAME
(
name
->
d
.
dirn
);
if
(
v
==
NULL
)
{
Py_DECREF
(
t
);
goto
fail
;
}
PyTuple_SET_ITEM
(
t
,
1
,
v
);
}
else
{
/* for everything else, we use the OpenSSL print form */
(
void
)
BIO_reset
(
biobuf
);
GENERAL_NAME_print
(
biobuf
,
name
);
len
=
BIO_gets
(
biobuf
,
buf
,
sizeof
(
buf
)
-
1
);
if
(
len
<
0
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
goto
fail
;
}
vptr
=
strchr
(
buf
,
':'
);
if
(
vptr
==
NULL
)
goto
fail
;
t
=
PyTuple_New
(
2
);
if
(
t
==
NULL
)
goto
fail
;
v
=
PyString_FromStringAndSize
(
buf
,
(
vptr
-
buf
));
if
(
v
==
NULL
)
{
Py_DECREF
(
t
);
goto
fail
;
}
PyTuple_SET_ITEM
(
t
,
0
,
v
);
v
=
PyString_FromStringAndSize
((
vptr
+
1
),
(
len
-
(
vptr
-
buf
+
1
)));
if
(
v
==
NULL
)
{
Py_DECREF
(
t
);
goto
fail
;
}
PyTuple_SET_ITEM
(
t
,
1
,
v
);
}
/* and add that rendering to the list */
if
(
PyList_Append
(
peer_alt_names
,
t
)
<
0
)
{
Py_DECREF
(
t
);
goto
fail
;
}
Py_DECREF
(
t
);
}
}
BIO_free
(
biobuf
);
if
(
peer_alt_names
!=
Py_None
)
{
v
=
PyList_AsTuple
(
peer_alt_names
);
Py_DECREF
(
peer_alt_names
);
return
v
;
}
else
{
return
peer_alt_names
;
}
if
(
certificate
==
NULL
)
return
peer_alt_names
;
/* get a memory buffer */
biobuf
=
BIO_new
(
BIO_s_mem
());
i
=
0
;
while
((
i
=
X509_get_ext_by_NID
(
certificate
,
NID_subject_alt_name
,
i
))
>=
0
)
{
if
(
peer_alt_names
==
Py_None
)
{
peer_alt_names
=
PyList_New
(
0
);
if
(
peer_alt_names
==
NULL
)
goto
fail
;
}
/* now decode the altName */
ext
=
X509_get_ext
(
certificate
,
i
);
if
(
!
(
method
=
X509V3_EXT_get
(
ext
)))
{
PyErr_SetString
(
PySSLErrorObject
,
ERRSTR
(
"No method for internalizing subjectAltName!"
));
goto
fail
;
}
p
=
ext
->
value
->
data
;
if
(
method
->
it
)
names
=
(
GENERAL_NAMES
*
)
(
ASN1_item_d2i
(
NULL
,
&
p
,
ext
->
value
->
length
,
ASN1_ITEM_ptr
(
method
->
it
)));
else
names
=
(
GENERAL_NAMES
*
)
(
method
->
d2i
(
NULL
,
&
p
,
ext
->
value
->
length
));
for
(
j
=
0
;
j
<
sk_GENERAL_NAME_num
(
names
);
j
++
)
{
/* get a rendering of each name in the set of names */
name
=
sk_GENERAL_NAME_value
(
names
,
j
);
if
(
name
->
type
==
GEN_DIRNAME
)
{
/* we special-case DirName as a tuple of tuples of attributes */
t
=
PyTuple_New
(
2
);
if
(
t
==
NULL
)
{
goto
fail
;
}
v
=
PyString_FromString
(
"DirName"
);
if
(
v
==
NULL
)
{
Py_DECREF
(
t
);
goto
fail
;
}
PyTuple_SET_ITEM
(
t
,
0
,
v
);
v
=
_create_tuple_for_X509_NAME
(
name
->
d
.
dirn
);
if
(
v
==
NULL
)
{
Py_DECREF
(
t
);
goto
fail
;
}
PyTuple_SET_ITEM
(
t
,
1
,
v
);
}
else
{
/* for everything else, we use the OpenSSL print form */
(
void
)
BIO_reset
(
biobuf
);
GENERAL_NAME_print
(
biobuf
,
name
);
len
=
BIO_gets
(
biobuf
,
buf
,
sizeof
(
buf
)
-
1
);
if
(
len
<
0
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
goto
fail
;
}
vptr
=
strchr
(
buf
,
':'
);
if
(
vptr
==
NULL
)
goto
fail
;
t
=
PyTuple_New
(
2
);
if
(
t
==
NULL
)
goto
fail
;
v
=
PyString_FromStringAndSize
(
buf
,
(
vptr
-
buf
));
if
(
v
==
NULL
)
{
Py_DECREF
(
t
);
goto
fail
;
}
PyTuple_SET_ITEM
(
t
,
0
,
v
);
v
=
PyString_FromStringAndSize
((
vptr
+
1
),
(
len
-
(
vptr
-
buf
+
1
)));
if
(
v
==
NULL
)
{
Py_DECREF
(
t
);
goto
fail
;
}
PyTuple_SET_ITEM
(
t
,
1
,
v
);
}
/* and add that rendering to the list */
if
(
PyList_Append
(
peer_alt_names
,
t
)
<
0
)
{
Py_DECREF
(
t
);
goto
fail
;
}
Py_DECREF
(
t
);
}
}
BIO_free
(
biobuf
);
if
(
peer_alt_names
!=
Py_None
)
{
v
=
PyList_AsTuple
(
peer_alt_names
);
Py_DECREF
(
peer_alt_names
);
return
v
;
}
else
{
return
peer_alt_names
;
}
fail:
if
(
biobuf
!=
NULL
)
BIO_free
(
biobuf
);
if
(
biobuf
!=
NULL
)
BIO_free
(
biobuf
);
if
(
peer_alt_names
!=
Py_None
)
{
Py_XDECREF
(
peer_alt_names
);
}
if
(
peer_alt_names
!=
Py_None
)
{
Py_XDECREF
(
peer_alt_names
);
}
return
NULL
;
return
NULL
;
}
static
PyObject
*
_decode_certificate
(
X509
*
certificate
,
int
verbose
)
{
PyObject
*
retval
=
NULL
;
BIO
*
biobuf
=
NULL
;
PyObject
*
peer
;
PyObject
*
peer_alt_names
=
NULL
;
PyObject
*
issuer
;
PyObject
*
version
;
PyObject
*
sn_obj
;
ASN1_INTEGER
*
serialNumber
;
char
buf
[
2048
];
int
len
;
ASN1_TIME
*
notBefore
,
*
notAfter
;
PyObject
*
pnotBefore
,
*
pnotAfter
;
retval
=
PyDict_New
();
if
(
retval
==
NULL
)
return
NULL
;
peer
=
_create_tuple_for_X509_NAME
(
X509_get_subject_name
(
certificate
));
if
(
peer
==
NULL
)
goto
fail0
;
if
(
PyDict_SetItemString
(
retval
,
(
const
char
*
)
"subject"
,
peer
)
<
0
)
{
Py_DECREF
(
peer
);
goto
fail0
;
}
Py_DECREF
(
peer
);
if
(
verbose
)
{
issuer
=
_create_tuple_for_X509_NAME
(
X509_get_issuer_name
(
certificate
));
if
(
issuer
==
NULL
)
goto
fail0
;
if
(
PyDict_SetItemString
(
retval
,
(
const
char
*
)
"issuer"
,
issuer
)
<
0
)
{
Py_DECREF
(
issuer
);
goto
fail0
;
}
Py_DECREF
(
issuer
);
version
=
PyInt_FromLong
(
X509_get_version
(
certificate
)
+
1
);
if
(
PyDict_SetItemString
(
retval
,
"version"
,
version
)
<
0
)
{
Py_DECREF
(
version
);
goto
fail0
;
}
Py_DECREF
(
version
);
}
/* get a memory buffer */
biobuf
=
BIO_new
(
BIO_s_mem
());
if
(
verbose
)
{
(
void
)
BIO_reset
(
biobuf
);
serialNumber
=
X509_get_serialNumber
(
certificate
);
/* should not exceed 20 octets, 160 bits, so buf is big enough */
i2a_ASN1_INTEGER
(
biobuf
,
serialNumber
);
len
=
BIO_gets
(
biobuf
,
buf
,
sizeof
(
buf
)
-
1
);
if
(
len
<
0
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
goto
fail1
;
}
sn_obj
=
PyString_FromStringAndSize
(
buf
,
len
);
if
(
sn_obj
==
NULL
)
goto
fail1
;
if
(
PyDict_SetItemString
(
retval
,
"serialNumber"
,
sn_obj
)
<
0
)
{
Py_DECREF
(
sn_obj
);
goto
fail1
;
}
Py_DECREF
(
sn_obj
);
(
void
)
BIO_reset
(
biobuf
);
notBefore
=
X509_get_notBefore
(
certificate
);
ASN1_TIME_print
(
biobuf
,
notBefore
);
len
=
BIO_gets
(
biobuf
,
buf
,
sizeof
(
buf
)
-
1
);
if
(
len
<
0
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
goto
fail1
;
}
pnotBefore
=
PyString_FromStringAndSize
(
buf
,
len
);
if
(
pnotBefore
==
NULL
)
goto
fail1
;
if
(
PyDict_SetItemString
(
retval
,
"notBefore"
,
pnotBefore
)
<
0
)
{
Py_DECREF
(
pnotBefore
);
goto
fail1
;
}
Py_DECREF
(
pnotBefore
);
}
(
void
)
BIO_reset
(
biobuf
);
notAfter
=
X509_get_notAfter
(
certificate
);
ASN1_TIME_print
(
biobuf
,
notAfter
);
len
=
BIO_gets
(
biobuf
,
buf
,
sizeof
(
buf
)
-
1
);
if
(
len
<
0
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
goto
fail1
;
}
pnotAfter
=
PyString_FromStringAndSize
(
buf
,
len
);
if
(
pnotAfter
==
NULL
)
goto
fail1
;
if
(
PyDict_SetItemString
(
retval
,
"notAfter"
,
pnotAfter
)
<
0
)
{
Py_DECREF
(
pnotAfter
);
goto
fail1
;
}
Py_DECREF
(
pnotAfter
);
/* Now look for subjectAltName */
peer_alt_names
=
_get_peer_alt_names
(
certificate
);
if
(
peer_alt_names
==
NULL
)
goto
fail1
;
else
if
(
peer_alt_names
!=
Py_None
)
{
if
(
PyDict_SetItemString
(
retval
,
"subjectAltName"
,
peer_alt_names
)
<
0
)
{
Py_DECREF
(
peer_alt_names
);
goto
fail1
;
}
Py_DECREF
(
peer_alt_names
);
}
BIO_free
(
biobuf
);
return
retval
;
PyObject
*
retval
=
NULL
;
BIO
*
biobuf
=
NULL
;
PyObject
*
peer
;
PyObject
*
peer_alt_names
=
NULL
;
PyObject
*
issuer
;
PyObject
*
version
;
PyObject
*
sn_obj
;
ASN1_INTEGER
*
serialNumber
;
char
buf
[
2048
];
int
len
;
ASN1_TIME
*
notBefore
,
*
notAfter
;
PyObject
*
pnotBefore
,
*
pnotAfter
;
retval
=
PyDict_New
();
if
(
retval
==
NULL
)
return
NULL
;
peer
=
_create_tuple_for_X509_NAME
(
X509_get_subject_name
(
certificate
));
if
(
peer
==
NULL
)
goto
fail0
;
if
(
PyDict_SetItemString
(
retval
,
(
const
char
*
)
"subject"
,
peer
)
<
0
)
{
Py_DECREF
(
peer
);
goto
fail0
;
}
Py_DECREF
(
peer
);
if
(
verbose
)
{
issuer
=
_create_tuple_for_X509_NAME
(
X509_get_issuer_name
(
certificate
));
if
(
issuer
==
NULL
)
goto
fail0
;
if
(
PyDict_SetItemString
(
retval
,
(
const
char
*
)
"issuer"
,
issuer
)
<
0
)
{
Py_DECREF
(
issuer
);
goto
fail0
;
}
Py_DECREF
(
issuer
);
version
=
PyInt_FromLong
(
X509_get_version
(
certificate
)
+
1
);
if
(
PyDict_SetItemString
(
retval
,
"version"
,
version
)
<
0
)
{
Py_DECREF
(
version
);
goto
fail0
;
}
Py_DECREF
(
version
);
}
/* get a memory buffer */
biobuf
=
BIO_new
(
BIO_s_mem
());
if
(
verbose
)
{
(
void
)
BIO_reset
(
biobuf
);
serialNumber
=
X509_get_serialNumber
(
certificate
);
/* should not exceed 20 octets, 160 bits, so buf is big enough */
i2a_ASN1_INTEGER
(
biobuf
,
serialNumber
);
len
=
BIO_gets
(
biobuf
,
buf
,
sizeof
(
buf
)
-
1
);
if
(
len
<
0
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
goto
fail1
;
}
sn_obj
=
PyString_FromStringAndSize
(
buf
,
len
);
if
(
sn_obj
==
NULL
)
goto
fail1
;
if
(
PyDict_SetItemString
(
retval
,
"serialNumber"
,
sn_obj
)
<
0
)
{
Py_DECREF
(
sn_obj
);
goto
fail1
;
}
Py_DECREF
(
sn_obj
);
(
void
)
BIO_reset
(
biobuf
);
notBefore
=
X509_get_notBefore
(
certificate
);
ASN1_TIME_print
(
biobuf
,
notBefore
);
len
=
BIO_gets
(
biobuf
,
buf
,
sizeof
(
buf
)
-
1
);
if
(
len
<
0
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
goto
fail1
;
}
pnotBefore
=
PyString_FromStringAndSize
(
buf
,
len
);
if
(
pnotBefore
==
NULL
)
goto
fail1
;
if
(
PyDict_SetItemString
(
retval
,
"notBefore"
,
pnotBefore
)
<
0
)
{
Py_DECREF
(
pnotBefore
);
goto
fail1
;
}
Py_DECREF
(
pnotBefore
);
}
(
void
)
BIO_reset
(
biobuf
);
notAfter
=
X509_get_notAfter
(
certificate
);
ASN1_TIME_print
(
biobuf
,
notAfter
);
len
=
BIO_gets
(
biobuf
,
buf
,
sizeof
(
buf
)
-
1
);
if
(
len
<
0
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
goto
fail1
;
}
pnotAfter
=
PyString_FromStringAndSize
(
buf
,
len
);
if
(
pnotAfter
==
NULL
)
goto
fail1
;
if
(
PyDict_SetItemString
(
retval
,
"notAfter"
,
pnotAfter
)
<
0
)
{
Py_DECREF
(
pnotAfter
);
goto
fail1
;
}
Py_DECREF
(
pnotAfter
);
/* Now look for subjectAltName */
peer_alt_names
=
_get_peer_alt_names
(
certificate
);
if
(
peer_alt_names
==
NULL
)
goto
fail1
;
else
if
(
peer_alt_names
!=
Py_None
)
{
if
(
PyDict_SetItemString
(
retval
,
"subjectAltName"
,
peer_alt_names
)
<
0
)
{
Py_DECREF
(
peer_alt_names
);
goto
fail1
;
}
Py_DECREF
(
peer_alt_names
);
}
BIO_free
(
biobuf
);
return
retval
;
fail1:
if
(
biobuf
!=
NULL
)
BIO_free
(
biobuf
);
if
(
biobuf
!=
NULL
)
BIO_free
(
biobuf
);
fail0:
Py_XDECREF
(
retval
);
return
NULL
;
Py_XDECREF
(
retval
);
return
NULL
;
}
static
PyObject
*
PySSL_test_decode_certificate
(
PyObject
*
mod
,
PyObject
*
args
)
{
PyObject
*
retval
=
NULL
;
char
*
filename
=
NULL
;
X509
*
x
=
NULL
;
BIO
*
cert
;
int
verbose
=
1
;
PyObject
*
retval
=
NULL
;
char
*
filename
=
NULL
;
X509
*
x
=
NULL
;
BIO
*
cert
;
int
verbose
=
1
;
if
(
!
PyArg_ParseTuple
(
args
,
"s|i:test_decode_certificate"
,
&
filename
,
&
verbose
))
return
NULL
;
if
(
!
PyArg_ParseTuple
(
args
,
"s|i:test_decode_certificate"
,
&
filename
,
&
verbose
))
return
NULL
;
if
((
cert
=
BIO_new
(
BIO_s_file
()))
==
NULL
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Can't malloc memory to read file"
);
goto
fail0
;
}
if
((
cert
=
BIO_new
(
BIO_s_file
()))
==
NULL
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Can't malloc memory to read file"
);
goto
fail0
;
}
if
(
BIO_read_filename
(
cert
,
filename
)
<=
0
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Can't open file"
);
goto
fail0
;
}
if
(
BIO_read_filename
(
cert
,
filename
)
<=
0
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Can't open file"
);
goto
fail0
;
}
x
=
PEM_read_bio_X509_AUX
(
cert
,
NULL
,
NULL
,
NULL
);
if
(
x
==
NULL
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Error decoding PEM-encoded file"
);
goto
fail0
;
}
x
=
PEM_read_bio_X509_AUX
(
cert
,
NULL
,
NULL
,
NULL
);
if
(
x
==
NULL
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Error decoding PEM-encoded file"
);
goto
fail0
;
}
retval
=
_decode_certificate
(
x
,
verbose
);
retval
=
_decode_certificate
(
x
,
verbose
);
fail0:
if
(
cert
!=
NULL
)
BIO_free
(
cert
);
return
retval
;
if
(
cert
!=
NULL
)
BIO_free
(
cert
);
return
retval
;
}
static
PyObject
*
PySSL_peercert
(
PySSLObject
*
self
,
PyObject
*
args
)
{
PyObject
*
retval
=
NULL
;
int
len
;
int
verification
;
PyObject
*
binary_mode
=
Py_None
;
if
(
!
PyArg_ParseTuple
(
args
,
"|O:peer_certificate"
,
&
binary_mode
))
return
NULL
;
if
(
!
self
->
peer_cert
)
Py_RETURN_NONE
;
if
(
PyObject_IsTrue
(
binary_mode
))
{
/* return cert in DER-encoded format */
unsigned
char
*
bytes_buf
=
NULL
;
bytes_buf
=
NULL
;
len
=
i2d_X509
(
self
->
peer_cert
,
&
bytes_buf
);
if
(
len
<
0
)
{
PySSL_SetError
(
self
,
len
,
__FILE__
,
__LINE__
);
return
NULL
;
}
retval
=
PyString_FromStringAndSize
((
const
char
*
)
bytes_buf
,
len
);
OPENSSL_free
(
bytes_buf
);
return
retval
;
}
else
{
verification
=
SSL_CTX_get_verify_mode
(
self
->
ctx
);
if
((
verification
&
SSL_VERIFY_PEER
)
==
0
)
return
PyDict_New
();
else
return
_decode_certificate
(
self
->
peer_cert
,
0
);
}
PyObject
*
retval
=
NULL
;
int
len
;
int
verification
;
PyObject
*
binary_mode
=
Py_None
;
if
(
!
PyArg_ParseTuple
(
args
,
"|O:peer_certificate"
,
&
binary_mode
))
return
NULL
;
if
(
!
self
->
peer_cert
)
Py_RETURN_NONE
;
if
(
PyObject_IsTrue
(
binary_mode
))
{
/* return cert in DER-encoded format */
unsigned
char
*
bytes_buf
=
NULL
;
bytes_buf
=
NULL
;
len
=
i2d_X509
(
self
->
peer_cert
,
&
bytes_buf
);
if
(
len
<
0
)
{
PySSL_SetError
(
self
,
len
,
__FILE__
,
__LINE__
);
return
NULL
;
}
retval
=
PyString_FromStringAndSize
((
const
char
*
)
bytes_buf
,
len
);
OPENSSL_free
(
bytes_buf
);
return
retval
;
}
else
{
verification
=
SSL_CTX_get_verify_mode
(
self
->
ctx
);
if
((
verification
&
SSL_VERIFY_PEER
)
==
0
)
return
PyDict_New
();
else
return
_decode_certificate
(
self
->
peer_cert
,
0
);
}
}
PyDoc_STRVAR
(
PySSL_peercert_doc
,
...
...
@@ -1040,60 +1040,60 @@ return the certificate even if it wasn't validated.");
static
PyObject
*
PySSL_cipher
(
PySSLObject
*
self
)
{
PyObject
*
retval
,
*
v
;
SSL_CIPHER
*
current
;
char
*
cipher_name
;
char
*
cipher_protocol
;
if
(
self
->
ssl
==
NULL
)
return
Py_None
;
current
=
SSL_get_current_cipher
(
self
->
ssl
);
if
(
current
==
NULL
)
return
Py_None
;
retval
=
PyTuple_New
(
3
);
if
(
retval
==
NULL
)
return
NULL
;
cipher_name
=
(
char
*
)
SSL_CIPHER_get_name
(
current
);
if
(
cipher_name
==
NULL
)
{
PyTuple_SET_ITEM
(
retval
,
0
,
Py_None
);
}
else
{
v
=
PyString_FromString
(
cipher_name
);
if
(
v
==
NULL
)
goto
fail0
;
PyTuple_SET_ITEM
(
retval
,
0
,
v
);
}
cipher_protocol
=
SSL_CIPHER_get_version
(
current
);
if
(
cipher_protocol
==
NULL
)
{
PyTuple_SET_ITEM
(
retval
,
1
,
Py_None
);
}
else
{
v
=
PyString_FromString
(
cipher_protocol
);
if
(
v
==
NULL
)
goto
fail0
;
PyTuple_SET_ITEM
(
retval
,
1
,
v
);
}
v
=
PyInt_FromLong
(
SSL_CIPHER_get_bits
(
current
,
NULL
));
if
(
v
==
NULL
)
goto
fail0
;
PyTuple_SET_ITEM
(
retval
,
2
,
v
);
return
retval
;
PyObject
*
retval
,
*
v
;
SSL_CIPHER
*
current
;
char
*
cipher_name
;
char
*
cipher_protocol
;
if
(
self
->
ssl
==
NULL
)
return
Py_None
;
current
=
SSL_get_current_cipher
(
self
->
ssl
);
if
(
current
==
NULL
)
return
Py_None
;
retval
=
PyTuple_New
(
3
);
if
(
retval
==
NULL
)
return
NULL
;
cipher_name
=
(
char
*
)
SSL_CIPHER_get_name
(
current
);
if
(
cipher_name
==
NULL
)
{
PyTuple_SET_ITEM
(
retval
,
0
,
Py_None
);
}
else
{
v
=
PyString_FromString
(
cipher_name
);
if
(
v
==
NULL
)
goto
fail0
;
PyTuple_SET_ITEM
(
retval
,
0
,
v
);
}
cipher_protocol
=
SSL_CIPHER_get_version
(
current
);
if
(
cipher_protocol
==
NULL
)
{
PyTuple_SET_ITEM
(
retval
,
1
,
Py_None
);
}
else
{
v
=
PyString_FromString
(
cipher_protocol
);
if
(
v
==
NULL
)
goto
fail0
;
PyTuple_SET_ITEM
(
retval
,
1
,
v
);
}
v
=
PyInt_FromLong
(
SSL_CIPHER_get_bits
(
current
,
NULL
));
if
(
v
==
NULL
)
goto
fail0
;
PyTuple_SET_ITEM
(
retval
,
2
,
v
);
return
retval
;
fail0:
Py_DECREF
(
retval
);
return
NULL
;
Py_DECREF
(
retval
);
return
NULL
;
}
static
void
PySSL_dealloc
(
PySSLObject
*
self
)
{
if
(
self
->
peer_cert
)
/* Possible not to have one? */
X509_free
(
self
->
peer_cert
);
if
(
self
->
ssl
)
SSL_free
(
self
->
ssl
);
if
(
self
->
ctx
)
SSL_CTX_free
(
self
->
ctx
);
Py_XDECREF
(
self
->
Socket
);
PyObject_Del
(
self
);
if
(
self
->
peer_cert
)
/* Possible not to have one? */
X509_free
(
self
->
peer_cert
);
if
(
self
->
ssl
)
SSL_free
(
self
->
ssl
);
if
(
self
->
ctx
)
SSL_CTX_free
(
self
->
ctx
);
Py_XDECREF
(
self
->
Socket
);
PyObject_Del
(
self
);
}
/* If the socket has a timeout, do a select()/poll() on the socket.
...
...
@@ -1104,137 +1104,137 @@ static void PySSL_dealloc(PySSLObject *self)
static
int
check_socket_and_wait_for_timeout
(
PySocketSockObject
*
s
,
int
writing
)
{
fd_set
fds
;
struct
timeval
tv
;
int
rc
;
/* Nothing to do unless we're in timeout mode (not non-blocking) */
if
(
s
->
sock_timeout
<
0
.
0
)
return
SOCKET_IS_BLOCKING
;
else
if
(
s
->
sock_timeout
==
0
.
0
)
return
SOCKET_IS_NONBLOCKING
;
/* Guard against closed socket */
if
(
s
->
sock_fd
<
0
)
return
SOCKET_HAS_BEEN_CLOSED
;
/* Prefer poll, if available, since you can poll() any fd
* which can't be done with select(). */
fd_set
fds
;
struct
timeval
tv
;
int
rc
;
/* Nothing to do unless we're in timeout mode (not non-blocking) */
if
(
s
->
sock_timeout
<
0
.
0
)
return
SOCKET_IS_BLOCKING
;
else
if
(
s
->
sock_timeout
==
0
.
0
)
return
SOCKET_IS_NONBLOCKING
;
/* Guard against closed socket */
if
(
s
->
sock_fd
<
0
)
return
SOCKET_HAS_BEEN_CLOSED
;
/* Prefer poll, if available, since you can poll() any fd
* which can't be done with select(). */
#ifdef HAVE_POLL
{
struct
pollfd
pollfd
;
int
timeout
;
{
struct
pollfd
pollfd
;
int
timeout
;
pollfd
.
fd
=
s
->
sock_fd
;
pollfd
.
events
=
writing
?
POLLOUT
:
POLLIN
;
pollfd
.
fd
=
s
->
sock_fd
;
pollfd
.
events
=
writing
?
POLLOUT
:
POLLIN
;
/* s->sock_timeout is in seconds, timeout in ms */
timeout
=
(
int
)(
s
->
sock_timeout
*
1000
+
0
.
5
);
PySSL_BEGIN_ALLOW_THREADS
rc
=
poll
(
&
pollfd
,
1
,
timeout
);
PySSL_END_ALLOW_THREADS
/* s->sock_timeout is in seconds, timeout in ms */
timeout
=
(
int
)(
s
->
sock_timeout
*
1000
+
0
.
5
);
PySSL_BEGIN_ALLOW_THREADS
rc
=
poll
(
&
pollfd
,
1
,
timeout
);
PySSL_END_ALLOW_THREADS
goto
normal_return
;
}
goto
normal_return
;
}
#endif
/* Guard against socket too large for select*/
/* Guard against socket too large for select*/
#ifndef Py_SOCKET_FD_CAN_BE_GE_FD_SETSIZE
if
(
s
->
sock_fd
>=
FD_SETSIZE
)
return
SOCKET_TOO_LARGE_FOR_SELECT
;
if
(
s
->
sock_fd
>=
FD_SETSIZE
)
return
SOCKET_TOO_LARGE_FOR_SELECT
;
#endif
/* Construct the arguments to select */
tv
.
tv_sec
=
(
int
)
s
->
sock_timeout
;
tv
.
tv_usec
=
(
int
)((
s
->
sock_timeout
-
tv
.
tv_sec
)
*
1e6
);
FD_ZERO
(
&
fds
);
FD_SET
(
s
->
sock_fd
,
&
fds
);
/* Construct the arguments to select */
tv
.
tv_sec
=
(
int
)
s
->
sock_timeout
;
tv
.
tv_usec
=
(
int
)((
s
->
sock_timeout
-
tv
.
tv_sec
)
*
1e6
);
FD_ZERO
(
&
fds
);
FD_SET
(
s
->
sock_fd
,
&
fds
);
/* See if the socket is ready */
PySSL_BEGIN_ALLOW_THREADS
if
(
writing
)
rc
=
select
(
s
->
sock_fd
+
1
,
NULL
,
&
fds
,
NULL
,
&
tv
);
else
rc
=
select
(
s
->
sock_fd
+
1
,
&
fds
,
NULL
,
NULL
,
&
tv
);
PySSL_END_ALLOW_THREADS
/* See if the socket is ready */
PySSL_BEGIN_ALLOW_THREADS
if
(
writing
)
rc
=
select
(
s
->
sock_fd
+
1
,
NULL
,
&
fds
,
NULL
,
&
tv
);
else
rc
=
select
(
s
->
sock_fd
+
1
,
&
fds
,
NULL
,
NULL
,
&
tv
);
PySSL_END_ALLOW_THREADS
#ifdef HAVE_POLL
normal_return:
#endif
/* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise
(when we are able to write or when there's something to read) */
return
rc
==
0
?
SOCKET_HAS_TIMED_OUT
:
SOCKET_OPERATION_OK
;
/* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise
(when we are able to write or when there's something to read) */
return
rc
==
0
?
SOCKET_HAS_TIMED_OUT
:
SOCKET_OPERATION_OK
;
}
static
PyObject
*
PySSL_SSLwrite
(
PySSLObject
*
self
,
PyObject
*
args
)
{
Py_buffer
buf
;
int
len
;
int
sockstate
;
int
err
;
int
nonblocking
;
if
(
!
PyArg_ParseTuple
(
args
,
"s*:write"
,
&
buf
))
return
NULL
;
/* just in case the blocking state of the socket has been changed */
nonblocking
=
(
self
->
Socket
->
sock_timeout
>=
0
.
0
);
BIO_set_nbio
(
SSL_get_rbio
(
self
->
ssl
),
nonblocking
);
BIO_set_nbio
(
SSL_get_wbio
(
self
->
ssl
),
nonblocking
);
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
1
);
if
(
sockstate
==
SOCKET_HAS_TIMED_OUT
)
{
PyErr_SetString
(
PySSLErrorObject
,
"The write operation timed out"
);
goto
error
;
}
else
if
(
sockstate
==
SOCKET_HAS_BEEN_CLOSED
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Underlying socket has been closed."
);
goto
error
;
}
else
if
(
sockstate
==
SOCKET_TOO_LARGE_FOR_SELECT
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Underlying socket too large for select()."
);
goto
error
;
}
do
{
PySSL_BEGIN_ALLOW_THREADS
len
=
SSL_write
(
self
->
ssl
,
buf
.
buf
,
buf
.
len
);
err
=
SSL_get_error
(
self
->
ssl
,
len
);
PySSL_END_ALLOW_THREADS
if
(
PyErr_CheckSignals
())
{
goto
error
;
}
if
(
err
==
SSL_ERROR_WANT_READ
)
{
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
0
);
}
else
if
(
err
==
SSL_ERROR_WANT_WRITE
)
{
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
1
);
}
else
{
sockstate
=
SOCKET_OPERATION_OK
;
}
if
(
sockstate
==
SOCKET_HAS_TIMED_OUT
)
{
PyErr_SetString
(
PySSLErrorObject
,
"The write operation timed out"
);
goto
error
;
}
else
if
(
sockstate
==
SOCKET_HAS_BEEN_CLOSED
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Underlying socket has been closed."
);
goto
error
;
}
else
if
(
sockstate
==
SOCKET_IS_NONBLOCKING
)
{
break
;
}
}
while
(
err
==
SSL_ERROR_WANT_READ
||
err
==
SSL_ERROR_WANT_WRITE
);
PyBuffer_Release
(
&
buf
);
if
(
len
>
0
)
return
PyInt_FromLong
(
len
);
else
return
PySSL_SetError
(
self
,
len
,
__FILE__
,
__LINE__
);
Py_buffer
buf
;
int
len
;
int
sockstate
;
int
err
;
int
nonblocking
;
if
(
!
PyArg_ParseTuple
(
args
,
"s*:write"
,
&
buf
))
return
NULL
;
/* just in case the blocking state of the socket has been changed */
nonblocking
=
(
self
->
Socket
->
sock_timeout
>=
0
.
0
);
BIO_set_nbio
(
SSL_get_rbio
(
self
->
ssl
),
nonblocking
);
BIO_set_nbio
(
SSL_get_wbio
(
self
->
ssl
),
nonblocking
);
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
1
);
if
(
sockstate
==
SOCKET_HAS_TIMED_OUT
)
{
PyErr_SetString
(
PySSLErrorObject
,
"The write operation timed out"
);
goto
error
;
}
else
if
(
sockstate
==
SOCKET_HAS_BEEN_CLOSED
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Underlying socket has been closed."
);
goto
error
;
}
else
if
(
sockstate
==
SOCKET_TOO_LARGE_FOR_SELECT
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Underlying socket too large for select()."
);
goto
error
;
}
do
{
PySSL_BEGIN_ALLOW_THREADS
len
=
SSL_write
(
self
->
ssl
,
buf
.
buf
,
buf
.
len
);
err
=
SSL_get_error
(
self
->
ssl
,
len
);
PySSL_END_ALLOW_THREADS
if
(
PyErr_CheckSignals
())
{
goto
error
;
}
if
(
err
==
SSL_ERROR_WANT_READ
)
{
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
0
);
}
else
if
(
err
==
SSL_ERROR_WANT_WRITE
)
{
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
1
);
}
else
{
sockstate
=
SOCKET_OPERATION_OK
;
}
if
(
sockstate
==
SOCKET_HAS_TIMED_OUT
)
{
PyErr_SetString
(
PySSLErrorObject
,
"The write operation timed out"
);
goto
error
;
}
else
if
(
sockstate
==
SOCKET_HAS_BEEN_CLOSED
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Underlying socket has been closed."
);
goto
error
;
}
else
if
(
sockstate
==
SOCKET_IS_NONBLOCKING
)
{
break
;
}
}
while
(
err
==
SSL_ERROR_WANT_READ
||
err
==
SSL_ERROR_WANT_WRITE
);
PyBuffer_Release
(
&
buf
);
if
(
len
>
0
)
return
PyInt_FromLong
(
len
);
else
return
PySSL_SetError
(
self
,
len
,
__FILE__
,
__LINE__
);
error:
PyBuffer_Release
(
&
buf
);
return
NULL
;
PyBuffer_Release
(
&
buf
);
return
NULL
;
}
PyDoc_STRVAR
(
PySSL_SSLwrite_doc
,
...
...
@@ -1245,15 +1245,15 @@ of bytes written.");
static
PyObject
*
PySSL_SSLpending
(
PySSLObject
*
self
)
{
int
count
=
0
;
PySSL_BEGIN_ALLOW_THREADS
count
=
SSL_pending
(
self
->
ssl
);
PySSL_END_ALLOW_THREADS
if
(
count
<
0
)
return
PySSL_SetError
(
self
,
count
,
__FILE__
,
__LINE__
);
else
return
PyInt_FromLong
(
count
);
int
count
=
0
;
PySSL_BEGIN_ALLOW_THREADS
count
=
SSL_pending
(
self
->
ssl
);
PySSL_END_ALLOW_THREADS
if
(
count
<
0
)
return
PySSL_SetError
(
self
,
count
,
__FILE__
,
__LINE__
);
else
return
PyInt_FromLong
(
count
);
}
PyDoc_STRVAR
(
PySSL_SSLpending_doc
,
...
...
@@ -1264,96 +1264,96 @@ pending on the connection.\n");
static
PyObject
*
PySSL_SSLread
(
PySSLObject
*
self
,
PyObject
*
args
)
{
PyObject
*
buf
;
int
count
=
0
;
int
len
=
1024
;
int
sockstate
;
int
err
;
int
nonblocking
;
if
(
!
PyArg_ParseTuple
(
args
,
"|i:read"
,
&
len
))
return
NULL
;
if
(
!
(
buf
=
PyString_FromStringAndSize
((
char
*
)
0
,
len
)))
return
NULL
;
/* just in case the blocking state of the socket has been changed */
nonblocking
=
(
self
->
Socket
->
sock_timeout
>=
0
.
0
);
BIO_set_nbio
(
SSL_get_rbio
(
self
->
ssl
),
nonblocking
);
BIO_set_nbio
(
SSL_get_wbio
(
self
->
ssl
),
nonblocking
);
/* first check if there are bytes ready to be read */
PySSL_BEGIN_ALLOW_THREADS
count
=
SSL_pending
(
self
->
ssl
);
PySSL_END_ALLOW_THREADS
if
(
!
count
)
{
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
0
);
if
(
sockstate
==
SOCKET_HAS_TIMED_OUT
)
{
PyErr_SetString
(
PySSLErrorObject
,
"The read operation timed out"
);
Py_DECREF
(
buf
);
return
NULL
;
}
else
if
(
sockstate
==
SOCKET_TOO_LARGE_FOR_SELECT
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Underlying socket too large for select()."
);
Py_DECREF
(
buf
);
return
NULL
;
}
else
if
(
sockstate
==
SOCKET_HAS_BEEN_CLOSED
)
{
if
(
SSL_get_shutdown
(
self
->
ssl
)
!=
SSL_RECEIVED_SHUTDOWN
)
{
Py_DECREF
(
buf
);
PyErr_SetString
(
PySSLErrorObject
,
"Socket closed without SSL shutdown handshake"
);
return
NULL
;
}
else
{
/* should contain a zero-length string */
_PyString_Resize
(
&
buf
,
0
);
return
buf
;
}
}
}
do
{
PySSL_BEGIN_ALLOW_THREADS
count
=
SSL_read
(
self
->
ssl
,
PyString_AsString
(
buf
),
len
);
err
=
SSL_get_error
(
self
->
ssl
,
count
);
PySSL_END_ALLOW_THREADS
if
(
PyErr_CheckSignals
())
{
Py_DECREF
(
buf
);
return
NULL
;
}
if
(
err
==
SSL_ERROR_WANT_READ
)
{
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
0
);
}
else
if
(
err
==
SSL_ERROR_WANT_WRITE
)
{
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
1
);
}
else
if
((
err
==
SSL_ERROR_ZERO_RETURN
)
&&
(
SSL_get_shutdown
(
self
->
ssl
)
==
SSL_RECEIVED_SHUTDOWN
))
{
_PyString_Resize
(
&
buf
,
0
);
return
buf
;
}
else
{
sockstate
=
SOCKET_OPERATION_OK
;
}
if
(
sockstate
==
SOCKET_HAS_TIMED_OUT
)
{
PyErr_SetString
(
PySSLErrorObject
,
"The read operation timed out"
);
Py_DECREF
(
buf
);
return
NULL
;
}
else
if
(
sockstate
==
SOCKET_IS_NONBLOCKING
)
{
break
;
}
}
while
(
err
==
SSL_ERROR_WANT_READ
||
err
==
SSL_ERROR_WANT_WRITE
);
if
(
count
<=
0
)
{
Py_DECREF
(
buf
);
return
PySSL_SetError
(
self
,
count
,
__FILE__
,
__LINE__
);
}
if
(
count
!=
len
)
_PyString_Resize
(
&
buf
,
count
);
return
buf
;
PyObject
*
buf
;
int
count
=
0
;
int
len
=
1024
;
int
sockstate
;
int
err
;
int
nonblocking
;
if
(
!
PyArg_ParseTuple
(
args
,
"|i:read"
,
&
len
))
return
NULL
;
if
(
!
(
buf
=
PyString_FromStringAndSize
((
char
*
)
0
,
len
)))
return
NULL
;
/* just in case the blocking state of the socket has been changed */
nonblocking
=
(
self
->
Socket
->
sock_timeout
>=
0
.
0
);
BIO_set_nbio
(
SSL_get_rbio
(
self
->
ssl
),
nonblocking
);
BIO_set_nbio
(
SSL_get_wbio
(
self
->
ssl
),
nonblocking
);
/* first check if there are bytes ready to be read */
PySSL_BEGIN_ALLOW_THREADS
count
=
SSL_pending
(
self
->
ssl
);
PySSL_END_ALLOW_THREADS
if
(
!
count
)
{
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
0
);
if
(
sockstate
==
SOCKET_HAS_TIMED_OUT
)
{
PyErr_SetString
(
PySSLErrorObject
,
"The read operation timed out"
);
Py_DECREF
(
buf
);
return
NULL
;
}
else
if
(
sockstate
==
SOCKET_TOO_LARGE_FOR_SELECT
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Underlying socket too large for select()."
);
Py_DECREF
(
buf
);
return
NULL
;
}
else
if
(
sockstate
==
SOCKET_HAS_BEEN_CLOSED
)
{
if
(
SSL_get_shutdown
(
self
->
ssl
)
!=
SSL_RECEIVED_SHUTDOWN
)
{
Py_DECREF
(
buf
);
PyErr_SetString
(
PySSLErrorObject
,
"Socket closed without SSL shutdown handshake"
);
return
NULL
;
}
else
{
/* should contain a zero-length string */
_PyString_Resize
(
&
buf
,
0
);
return
buf
;
}
}
}
do
{
PySSL_BEGIN_ALLOW_THREADS
count
=
SSL_read
(
self
->
ssl
,
PyString_AsString
(
buf
),
len
);
err
=
SSL_get_error
(
self
->
ssl
,
count
);
PySSL_END_ALLOW_THREADS
if
(
PyErr_CheckSignals
())
{
Py_DECREF
(
buf
);
return
NULL
;
}
if
(
err
==
SSL_ERROR_WANT_READ
)
{
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
0
);
}
else
if
(
err
==
SSL_ERROR_WANT_WRITE
)
{
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
1
);
}
else
if
((
err
==
SSL_ERROR_ZERO_RETURN
)
&&
(
SSL_get_shutdown
(
self
->
ssl
)
==
SSL_RECEIVED_SHUTDOWN
))
{
_PyString_Resize
(
&
buf
,
0
);
return
buf
;
}
else
{
sockstate
=
SOCKET_OPERATION_OK
;
}
if
(
sockstate
==
SOCKET_HAS_TIMED_OUT
)
{
PyErr_SetString
(
PySSLErrorObject
,
"The read operation timed out"
);
Py_DECREF
(
buf
);
return
NULL
;
}
else
if
(
sockstate
==
SOCKET_IS_NONBLOCKING
)
{
break
;
}
}
while
(
err
==
SSL_ERROR_WANT_READ
||
err
==
SSL_ERROR_WANT_WRITE
);
if
(
count
<=
0
)
{
Py_DECREF
(
buf
);
return
PySSL_SetError
(
self
,
count
,
__FILE__
,
__LINE__
);
}
if
(
count
!=
len
)
_PyString_Resize
(
&
buf
,
count
);
return
buf
;
}
PyDoc_STRVAR
(
PySSL_SSLread_doc
,
...
...
@@ -1363,82 +1363,82 @@ Read up to len bytes from the SSL socket.");
static
PyObject
*
PySSL_SSLshutdown
(
PySSLObject
*
self
)
{
int
err
,
ssl_err
,
sockstate
,
nonblocking
;
int
zeros
=
0
;
/* Guard against closed socket */
if
(
self
->
Socket
->
sock_fd
<
0
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Underlying socket has been closed."
);
return
NULL
;
}
/* Just in case the blocking state of the socket has been changed */
nonblocking
=
(
self
->
Socket
->
sock_timeout
>=
0
.
0
);
BIO_set_nbio
(
SSL_get_rbio
(
self
->
ssl
),
nonblocking
);
BIO_set_nbio
(
SSL_get_wbio
(
self
->
ssl
),
nonblocking
);
while
(
1
)
{
PySSL_BEGIN_ALLOW_THREADS
/* Disable read-ahead so that unwrap can work correctly.
* Otherwise OpenSSL might read in too much data,
* eating clear text data that happens to be
* transmitted after the SSL shutdown.
* Should be safe to call repeatedly everytime this
* function is used and the shutdown_seen_zero != 0
* condition is met.
*/
if
(
self
->
shutdown_seen_zero
)
SSL_set_read_ahead
(
self
->
ssl
,
0
);
err
=
SSL_shutdown
(
self
->
ssl
);
PySSL_END_ALLOW_THREADS
/* If err == 1, a secure shutdown with SSL_shutdown() is complete */
if
(
err
>
0
)
break
;
if
(
err
==
0
)
{
/* Don't loop endlessly; instead preserve legacy
behaviour of trying SSL_shutdown() only twice.
This looks necessary for OpenSSL < 0.9.8m */
if
(
++
zeros
>
1
)
break
;
/* Shutdown was sent, now try receiving */
self
->
shutdown_seen_zero
=
1
;
continue
;
}
/* Possibly retry shutdown until timeout or failure */
ssl_err
=
SSL_get_error
(
self
->
ssl
,
err
);
if
(
ssl_err
==
SSL_ERROR_WANT_READ
)
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
0
);
else
if
(
ssl_err
==
SSL_ERROR_WANT_WRITE
)
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
1
);
else
break
;
if
(
sockstate
==
SOCKET_HAS_TIMED_OUT
)
{
if
(
ssl_err
==
SSL_ERROR_WANT_READ
)
PyErr_SetString
(
PySSLErrorObject
,
"The read operation timed out"
);
else
PyErr_SetString
(
PySSLErrorObject
,
"The write operation timed out"
);
return
NULL
;
}
else
if
(
sockstate
==
SOCKET_TOO_LARGE_FOR_SELECT
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Underlying socket too large for select()."
);
return
NULL
;
}
else
if
(
sockstate
!=
SOCKET_OPERATION_OK
)
/* Retain the SSL error code */
break
;
}
if
(
err
<
0
)
return
PySSL_SetError
(
self
,
err
,
__FILE__
,
__LINE__
);
else
{
Py_INCREF
(
self
->
Socket
);
return
(
PyObject
*
)
(
self
->
Socket
);
}
int
err
,
ssl_err
,
sockstate
,
nonblocking
;
int
zeros
=
0
;
/* Guard against closed socket */
if
(
self
->
Socket
->
sock_fd
<
0
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Underlying socket has been closed."
);
return
NULL
;
}
/* Just in case the blocking state of the socket has been changed */
nonblocking
=
(
self
->
Socket
->
sock_timeout
>=
0
.
0
);
BIO_set_nbio
(
SSL_get_rbio
(
self
->
ssl
),
nonblocking
);
BIO_set_nbio
(
SSL_get_wbio
(
self
->
ssl
),
nonblocking
);
while
(
1
)
{
PySSL_BEGIN_ALLOW_THREADS
/* Disable read-ahead so that unwrap can work correctly.
* Otherwise OpenSSL might read in too much data,
* eating clear text data that happens to be
* transmitted after the SSL shutdown.
* Should be safe to call repeatedly everytime this
* function is used and the shutdown_seen_zero != 0
* condition is met.
*/
if
(
self
->
shutdown_seen_zero
)
SSL_set_read_ahead
(
self
->
ssl
,
0
);
err
=
SSL_shutdown
(
self
->
ssl
);
PySSL_END_ALLOW_THREADS
/* If err == 1, a secure shutdown with SSL_shutdown() is complete */
if
(
err
>
0
)
break
;
if
(
err
==
0
)
{
/* Don't loop endlessly; instead preserve legacy
behaviour of trying SSL_shutdown() only twice.
This looks necessary for OpenSSL < 0.9.8m */
if
(
++
zeros
>
1
)
break
;
/* Shutdown was sent, now try receiving */
self
->
shutdown_seen_zero
=
1
;
continue
;
}
/* Possibly retry shutdown until timeout or failure */
ssl_err
=
SSL_get_error
(
self
->
ssl
,
err
);
if
(
ssl_err
==
SSL_ERROR_WANT_READ
)
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
0
);
else
if
(
ssl_err
==
SSL_ERROR_WANT_WRITE
)
sockstate
=
check_socket_and_wait_for_timeout
(
self
->
Socket
,
1
);
else
break
;
if
(
sockstate
==
SOCKET_HAS_TIMED_OUT
)
{
if
(
ssl_err
==
SSL_ERROR_WANT_READ
)
PyErr_SetString
(
PySSLErrorObject
,
"The read operation timed out"
);
else
PyErr_SetString
(
PySSLErrorObject
,
"The write operation timed out"
);
return
NULL
;
}
else
if
(
sockstate
==
SOCKET_TOO_LARGE_FOR_SELECT
)
{
PyErr_SetString
(
PySSLErrorObject
,
"Underlying socket too large for select()."
);
return
NULL
;
}
else
if
(
sockstate
!=
SOCKET_OPERATION_OK
)
/* Retain the SSL error code */
break
;
}
if
(
err
<
0
)
return
PySSL_SetError
(
self
,
err
,
__FILE__
,
__LINE__
);
else
{
Py_INCREF
(
self
->
Socket
);
return
(
PyObject
*
)
(
self
->
Socket
);
}
}
PyDoc_STRVAR
(
PySSL_SSLshutdown_doc
,
...
...
@@ -1448,44 +1448,44 @@ Does the SSL shutdown handshake with the remote end, and returns\n\
the underlying socket object."
);
static
PyMethodDef
PySSLMethods
[]
=
{
{
"do_handshake"
,
(
PyCFunction
)
PySSL_SSLdo_handshake
,
METH_NOARGS
},
{
"write"
,
(
PyCFunction
)
PySSL_SSLwrite
,
METH_VARARGS
,
PySSL_SSLwrite_doc
},
{
"read"
,
(
PyCFunction
)
PySSL_SSLread
,
METH_VARARGS
,
PySSL_SSLread_doc
},
{
"pending"
,
(
PyCFunction
)
PySSL_SSLpending
,
METH_NOARGS
,
PySSL_SSLpending_doc
},
{
"server"
,
(
PyCFunction
)
PySSL_server
,
METH_NOARGS
},
{
"issuer"
,
(
PyCFunction
)
PySSL_issuer
,
METH_NOARGS
},
{
"peer_certificate"
,
(
PyCFunction
)
PySSL_peercert
,
METH_VARARGS
,
PySSL_peercert_doc
},
{
"cipher"
,
(
PyCFunction
)
PySSL_cipher
,
METH_NOARGS
},
{
"shutdown"
,
(
PyCFunction
)
PySSL_SSLshutdown
,
METH_NOARGS
,
PySSL_SSLshutdown_doc
},
{
NULL
,
NULL
}
{
"do_handshake"
,
(
PyCFunction
)
PySSL_SSLdo_handshake
,
METH_NOARGS
},
{
"write"
,
(
PyCFunction
)
PySSL_SSLwrite
,
METH_VARARGS
,
PySSL_SSLwrite_doc
},
{
"read"
,
(
PyCFunction
)
PySSL_SSLread
,
METH_VARARGS
,
PySSL_SSLread_doc
},
{
"pending"
,
(
PyCFunction
)
PySSL_SSLpending
,
METH_NOARGS
,
PySSL_SSLpending_doc
},
{
"server"
,
(
PyCFunction
)
PySSL_server
,
METH_NOARGS
},
{
"issuer"
,
(
PyCFunction
)
PySSL_issuer
,
METH_NOARGS
},
{
"peer_certificate"
,
(
PyCFunction
)
PySSL_peercert
,
METH_VARARGS
,
PySSL_peercert_doc
},
{
"cipher"
,
(
PyCFunction
)
PySSL_cipher
,
METH_NOARGS
},
{
"shutdown"
,
(
PyCFunction
)
PySSL_SSLshutdown
,
METH_NOARGS
,
PySSL_SSLshutdown_doc
},
{
NULL
,
NULL
}
};
static
PyObject
*
PySSL_getattr
(
PySSLObject
*
self
,
char
*
name
)
{
return
Py_FindMethod
(
PySSLMethods
,
(
PyObject
*
)
self
,
name
);
return
Py_FindMethod
(
PySSLMethods
,
(
PyObject
*
)
self
,
name
);
}
static
PyTypeObject
PySSL_Type
=
{
PyVarObject_HEAD_INIT
(
NULL
,
0
)
"ssl.SSLContext"
,
/*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*/
PyVarObject_HEAD_INIT
(
NULL
,
0
)
"ssl.SSLContext"
,
/*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*/
};
#ifdef HAVE_OPENSSL_RAND
...
...
@@ -1499,7 +1499,7 @@ PySSL_RAND_add(PyObject *self, PyObject *args)
double
entropy
;
if
(
!
PyArg_ParseTuple
(
args
,
"s#d:RAND_add"
,
&
buf
,
&
len
,
&
entropy
))
return
NULL
;
return
NULL
;
RAND_add
(
buf
,
len
,
entropy
);
Py_INCREF
(
Py_None
);
return
Py_None
;
...
...
@@ -1530,15 +1530,15 @@ PySSL_RAND_egd(PyObject *self, PyObject *arg)
int
bytes
;
if
(
!
PyString_Check
(
arg
))
return
PyErr_Format
(
PyExc_TypeError
,
"RAND_egd() expected string, found %s"
,
Py_TYPE
(
arg
)
->
tp_name
);
return
PyErr_Format
(
PyExc_TypeError
,
"RAND_egd() expected string, found %s"
,
Py_TYPE
(
arg
)
->
tp_name
);
bytes
=
RAND_egd
(
PyString_AS_STRING
(
arg
));
if
(
bytes
==
-
1
)
{
PyErr_SetString
(
PySSLErrorObject
,
"EGD connection failed or EGD did not return "
"enough data to seed the PRNG"
);
return
NULL
;
PyErr_SetString
(
PySSLErrorObject
,
"EGD connection failed or EGD did not return "
"enough data to seed the PRNG"
);
return
NULL
;
}
return
PyInt_FromLong
(
bytes
);
}
...
...
@@ -1555,19 +1555,19 @@ fails or if it does provide enough data to seed PRNG.");
/* List of functions exported by this module. */
static
PyMethodDef
PySSL_methods
[]
=
{
{
"sslwrap"
,
PySSL_sslwrap
,
METH_VARARGS
,
ssl_doc
},
{
"_test_decode_cert"
,
PySSL_test_decode_certificate
,
METH_VARARGS
},
{
"sslwrap"
,
PySSL_sslwrap
,
METH_VARARGS
,
ssl_doc
},
{
"_test_decode_cert"
,
PySSL_test_decode_certificate
,
METH_VARARGS
},
#ifdef HAVE_OPENSSL_RAND
{
"RAND_add"
,
PySSL_RAND_add
,
METH_VARARGS
,
PySSL_RAND_add_doc
},
{
"RAND_egd"
,
PySSL_RAND_egd
,
METH_O
,
PySSL_RAND_egd_doc
},
{
"RAND_status"
,
(
PyCFunction
)
PySSL_RAND_status
,
METH_NOARGS
,
PySSL_RAND_status_doc
},
{
"RAND_add"
,
PySSL_RAND_add
,
METH_VARARGS
,
PySSL_RAND_add_doc
},
{
"RAND_egd"
,
PySSL_RAND_egd
,
METH_O
,
PySSL_RAND_egd_doc
},
{
"RAND_status"
,
(
PyCFunction
)
PySSL_RAND_status
,
METH_NOARGS
,
PySSL_RAND_status_doc
},
#endif
{
NULL
,
NULL
}
/* Sentinel */
{
NULL
,
NULL
}
/* Sentinel */
};
...
...
@@ -1579,64 +1579,64 @@ static PyMethodDef PySSL_methods[] = {
static
PyThread_type_lock
*
_ssl_locks
=
NULL
;
static
unsigned
long
_ssl_thread_id_function
(
void
)
{
return
PyThread_get_thread_ident
();
return
PyThread_get_thread_ident
();
}
static
void
_ssl_thread_locking_function
(
int
mode
,
int
n
,
const
char
*
file
,
int
line
)
{
/* this function is needed to perform locking on shared data
structures. (Note that OpenSSL uses a number of global data
structures that will be implicitly shared whenever multiple threads
use OpenSSL.) Multi-threaded applications will crash at random if
it is not set.
locking_function() must be able to handle up to CRYPTO_num_locks()
different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and
releases it otherwise.
file and line are the file number of the function setting the
lock. They can be useful for debugging.
*/
if
((
_ssl_locks
==
NULL
)
||
(
n
<
0
)
||
((
unsigned
)
n
>=
_ssl_locks_count
))
return
;
if
(
mode
&
CRYPTO_LOCK
)
{
PyThread_acquire_lock
(
_ssl_locks
[
n
],
1
);
}
else
{
PyThread_release_lock
(
_ssl_locks
[
n
]);
}
/* this function is needed to perform locking on shared data
structures. (Note that OpenSSL uses a number of global data
structures that will be implicitly shared whenever multiple threads
use OpenSSL.) Multi-threaded applications will crash at random if
it is not set.
locking_function() must be able to handle up to CRYPTO_num_locks()
different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and
releases it otherwise.
file and line are the file number of the function setting the
lock. They can be useful for debugging.
*/
if
((
_ssl_locks
==
NULL
)
||
(
n
<
0
)
||
((
unsigned
)
n
>=
_ssl_locks_count
))
return
;
if
(
mode
&
CRYPTO_LOCK
)
{
PyThread_acquire_lock
(
_ssl_locks
[
n
],
1
);
}
else
{
PyThread_release_lock
(
_ssl_locks
[
n
]);
}
}
static
int
_setup_ssl_threads
(
void
)
{
unsigned
int
i
;
if
(
_ssl_locks
==
NULL
)
{
_ssl_locks_count
=
CRYPTO_num_locks
();
_ssl_locks
=
(
PyThread_type_lock
*
)
malloc
(
sizeof
(
PyThread_type_lock
)
*
_ssl_locks_count
);
if
(
_ssl_locks
==
NULL
)
return
0
;
memset
(
_ssl_locks
,
0
,
sizeof
(
PyThread_type_lock
)
*
_ssl_locks_count
);
for
(
i
=
0
;
i
<
_ssl_locks_count
;
i
++
)
{
_ssl_locks
[
i
]
=
PyThread_allocate_lock
();
if
(
_ssl_locks
[
i
]
==
NULL
)
{
unsigned
int
j
;
for
(
j
=
0
;
j
<
i
;
j
++
)
{
PyThread_free_lock
(
_ssl_locks
[
j
]);
}
free
(
_ssl_locks
);
return
0
;
}
}
CRYPTO_set_locking_callback
(
_ssl_thread_locking_function
);
CRYPTO_set_id_callback
(
_ssl_thread_id_function
);
}
return
1
;
unsigned
int
i
;
if
(
_ssl_locks
==
NULL
)
{
_ssl_locks_count
=
CRYPTO_num_locks
();
_ssl_locks
=
(
PyThread_type_lock
*
)
malloc
(
sizeof
(
PyThread_type_lock
)
*
_ssl_locks_count
);
if
(
_ssl_locks
==
NULL
)
return
0
;
memset
(
_ssl_locks
,
0
,
sizeof
(
PyThread_type_lock
)
*
_ssl_locks_count
);
for
(
i
=
0
;
i
<
_ssl_locks_count
;
i
++
)
{
_ssl_locks
[
i
]
=
PyThread_allocate_lock
();
if
(
_ssl_locks
[
i
]
==
NULL
)
{
unsigned
int
j
;
for
(
j
=
0
;
j
<
i
;
j
++
)
{
PyThread_free_lock
(
_ssl_locks
[
j
]);
}
free
(
_ssl_locks
);
return
0
;
}
}
CRYPTO_set_locking_callback
(
_ssl_thread_locking_function
);
CRYPTO_set_id_callback
(
_ssl_thread_id_function
);
}
return
1
;
}
#endif
/* def HAVE_THREAD */
#endif
/* def HAVE_THREAD */
PyDoc_STRVAR
(
module_doc
,
"Implementation module for SSL socket operations. See the socket module
\n
\
...
...
@@ -1645,103 +1645,103 @@ for documentation.");
PyMODINIT_FUNC
init_ssl
(
void
)
{
PyObject
*
m
,
*
d
,
*
r
;
unsigned
long
libver
;
unsigned
int
major
,
minor
,
fix
,
patch
,
status
;
PyObject
*
m
,
*
d
,
*
r
;
unsigned
long
libver
;
unsigned
int
major
,
minor
,
fix
,
patch
,
status
;
Py_TYPE
(
&
PySSL_Type
)
=
&
PyType_Type
;
Py_TYPE
(
&
PySSL_Type
)
=
&
PyType_Type
;
m
=
Py_InitModule3
(
"_ssl"
,
PySSL_methods
,
module_doc
);
if
(
m
==
NULL
)
return
;
d
=
PyModule_GetDict
(
m
);
m
=
Py_InitModule3
(
"_ssl"
,
PySSL_methods
,
module_doc
);
if
(
m
==
NULL
)
return
;
d
=
PyModule_GetDict
(
m
);
/* Load _socket module and its C API */
if
(
PySocketModule_ImportModuleAndAPI
())
return
;
/* Load _socket module and its C API */
if
(
PySocketModule_ImportModuleAndAPI
())
return
;
/* Init OpenSSL */
SSL_load_error_strings
();
SSL_library_init
();
/* Init OpenSSL */
SSL_load_error_strings
();
SSL_library_init
();
#ifdef WITH_THREAD
/* note that this will start threading if not already started */
if
(
!
_setup_ssl_threads
())
{
return
;
}
/* note that this will start threading if not already started */
if
(
!
_setup_ssl_threads
())
{
return
;
}
#endif
OpenSSL_add_all_algorithms
();
/* Add symbols to module dict */
PySSLErrorObject
=
PyErr_NewException
(
"ssl.SSLError"
,
PySocketModule
.
error
,
NULL
);
if
(
PySSLErrorObject
==
NULL
)
return
;
if
(
PyDict_SetItemString
(
d
,
"SSLError"
,
PySSLErrorObject
)
!=
0
)
return
;
if
(
PyDict_SetItemString
(
d
,
"SSLType"
,
(
PyObject
*
)
&
PySSL_Type
)
!=
0
)
return
;
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_ZERO_RETURN"
,
PY_SSL_ERROR_ZERO_RETURN
);
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_WANT_READ"
,
PY_SSL_ERROR_WANT_READ
);
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_WANT_WRITE"
,
PY_SSL_ERROR_WANT_WRITE
);
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_WANT_X509_LOOKUP"
,
PY_SSL_ERROR_WANT_X509_LOOKUP
);
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_SYSCALL"
,
PY_SSL_ERROR_SYSCALL
);
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_SSL"
,
PY_SSL_ERROR_SSL
);
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_WANT_CONNECT"
,
PY_SSL_ERROR_WANT_CONNECT
);
/* non ssl.h errorcodes */
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_EOF"
,
PY_SSL_ERROR_EOF
);
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_INVALID_ERROR_CODE"
,
PY_SSL_ERROR_INVALID_ERROR_CODE
);
/* cert requirements */
PyModule_AddIntConstant
(
m
,
"CERT_NONE"
,
PY_SSL_CERT_NONE
);
PyModule_AddIntConstant
(
m
,
"CERT_OPTIONAL"
,
PY_SSL_CERT_OPTIONAL
);
PyModule_AddIntConstant
(
m
,
"CERT_REQUIRED"
,
PY_SSL_CERT_REQUIRED
);
/* protocol versions */
PyModule_AddIntConstant
(
m
,
"PROTOCOL_SSLv2"
,
PY_SSL_VERSION_SSL2
);
PyModule_AddIntConstant
(
m
,
"PROTOCOL_SSLv3"
,
PY_SSL_VERSION_SSL3
);
PyModule_AddIntConstant
(
m
,
"PROTOCOL_SSLv23"
,
PY_SSL_VERSION_SSL23
);
PyModule_AddIntConstant
(
m
,
"PROTOCOL_TLSv1"
,
PY_SSL_VERSION_TLS1
);
/* OpenSSL version */
/* SSLeay() gives us the version of the library linked against,
which could be different from the headers version.
*/
libver
=
SSLeay
();
r
=
PyLong_FromUnsignedLong
(
libver
);
if
(
r
==
NULL
)
return
;
if
(
PyModule_AddObject
(
m
,
"OPENSSL_VERSION_NUMBER"
,
r
))
return
;
status
=
libver
&
0xF
;
libver
>>=
4
;
patch
=
libver
&
0xFF
;
libver
>>=
8
;
fix
=
libver
&
0xFF
;
libver
>>=
8
;
minor
=
libver
&
0xFF
;
libver
>>=
8
;
major
=
libver
&
0xFF
;
r
=
Py_BuildValue
(
"IIIII"
,
major
,
minor
,
fix
,
patch
,
status
);
if
(
r
==
NULL
||
PyModule_AddObject
(
m
,
"OPENSSL_VERSION_INFO"
,
r
))
return
;
r
=
PyString_FromString
(
SSLeay_version
(
SSLEAY_VERSION
));
if
(
r
==
NULL
||
PyModule_AddObject
(
m
,
"OPENSSL_VERSION"
,
r
))
return
;
OpenSSL_add_all_algorithms
();
/* Add symbols to module dict */
PySSLErrorObject
=
PyErr_NewException
(
"ssl.SSLError"
,
PySocketModule
.
error
,
NULL
);
if
(
PySSLErrorObject
==
NULL
)
return
;
if
(
PyDict_SetItemString
(
d
,
"SSLError"
,
PySSLErrorObject
)
!=
0
)
return
;
if
(
PyDict_SetItemString
(
d
,
"SSLType"
,
(
PyObject
*
)
&
PySSL_Type
)
!=
0
)
return
;
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_ZERO_RETURN"
,
PY_SSL_ERROR_ZERO_RETURN
);
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_WANT_READ"
,
PY_SSL_ERROR_WANT_READ
);
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_WANT_WRITE"
,
PY_SSL_ERROR_WANT_WRITE
);
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_WANT_X509_LOOKUP"
,
PY_SSL_ERROR_WANT_X509_LOOKUP
);
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_SYSCALL"
,
PY_SSL_ERROR_SYSCALL
);
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_SSL"
,
PY_SSL_ERROR_SSL
);
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_WANT_CONNECT"
,
PY_SSL_ERROR_WANT_CONNECT
);
/* non ssl.h errorcodes */
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_EOF"
,
PY_SSL_ERROR_EOF
);
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_INVALID_ERROR_CODE"
,
PY_SSL_ERROR_INVALID_ERROR_CODE
);
/* cert requirements */
PyModule_AddIntConstant
(
m
,
"CERT_NONE"
,
PY_SSL_CERT_NONE
);
PyModule_AddIntConstant
(
m
,
"CERT_OPTIONAL"
,
PY_SSL_CERT_OPTIONAL
);
PyModule_AddIntConstant
(
m
,
"CERT_REQUIRED"
,
PY_SSL_CERT_REQUIRED
);
/* protocol versions */
PyModule_AddIntConstant
(
m
,
"PROTOCOL_SSLv2"
,
PY_SSL_VERSION_SSL2
);
PyModule_AddIntConstant
(
m
,
"PROTOCOL_SSLv3"
,
PY_SSL_VERSION_SSL3
);
PyModule_AddIntConstant
(
m
,
"PROTOCOL_SSLv23"
,
PY_SSL_VERSION_SSL23
);
PyModule_AddIntConstant
(
m
,
"PROTOCOL_TLSv1"
,
PY_SSL_VERSION_TLS1
);
/* OpenSSL version */
/* SSLeay() gives us the version of the library linked against,
which could be different from the headers version.
*/
libver
=
SSLeay
();
r
=
PyLong_FromUnsignedLong
(
libver
);
if
(
r
==
NULL
)
return
;
if
(
PyModule_AddObject
(
m
,
"OPENSSL_VERSION_NUMBER"
,
r
))
return
;
status
=
libver
&
0xF
;
libver
>>=
4
;
patch
=
libver
&
0xFF
;
libver
>>=
8
;
fix
=
libver
&
0xFF
;
libver
>>=
8
;
minor
=
libver
&
0xFF
;
libver
>>=
8
;
major
=
libver
&
0xFF
;
r
=
Py_BuildValue
(
"IIIII"
,
major
,
minor
,
fix
,
patch
,
status
);
if
(
r
==
NULL
||
PyModule_AddObject
(
m
,
"OPENSSL_VERSION_INFO"
,
r
))
return
;
r
=
PyString_FromString
(
SSLeay_version
(
SSLEAY_VERSION
));
if
(
r
==
NULL
||
PyModule_AddObject
(
m
,
"OPENSSL_VERSION"
,
r
))
return
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment