Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ruanhaishen
hiredis
Commits
190bca88
Commit
190bca88
authored
May 22, 2020
by
Yossi Gottlieb
Browse files
New SSL API to replace redisSecureConnection().
parent
8e0264cf
Changes
6
Hide whitespace changes
Inline
Side-by-side
README.md
View file @
190bca88
...
...
@@ -438,42 +438,68 @@ First, you'll need to make sure you include the SSL header file:
#include "hiredis_ssl.h"
```
SSL can only be enabled on a
`redisContext`
connection after the connection has
been established and before any command has been processed. For example:
You will also need to link against
`libhiredis_ssl`
,
**in addition**
to
`libhiredis`
and add
`-lssl -lcrypto`
to satisfy its dependencies.
Hiredis implements SSL/TLS on top of its normal
`redisContext`
or
`redisAsyncContext`
, so you will need to establish a connection first and then
initiate an SSL/TLS handshake.
#### Hiredis OpenSSL Wrappers
Before Hiredis can negotiate an SSL/TLS connection, it is necessary to
initialize OpenSSL and create a context. You can do that in two ways:
1.
Work directly with the OpenSSL API to initialize the library's global context
and create
`SSL_CTX *`
and
`SSL *`
contexts. With an
`SSL *`
object you can
call
`redisInitiateSSL()`
.
2.
Work with a set of Hiredis-provided wrappers around OpenSSL, create a
`redisSSLContext`
object to hold configuration and use
`redisInitiateSSLWithContext()`
to initiate the SSL/TLS handshake.
```
c
/* An Hiredis SSL context. It holds SSL configuration and can be reused across
* many contexts.
*/
redisSSLContext
*
ssl
;
/* An error variable to indicate what went wrong, if the context fails to
* initialize.
*/
redisSSLContextError
ssl_error
;
/* Initialize global OpenSSL state.
*
* You should call this only once when your app initializes, and only if
* you don't explicitly or implicitly initialize OpenSSL it elsewhere.
*/
redisInitOpenSSL
();
/* Create SSL context */
ssl
=
redisCreateSSLContext
(
"cacertbundle.crt"
,
/* File name of trusted CA/ca bundle file, optional */
"/path/to/certs"
,
/* Path of trusted certificates, optional */
"client_cert.pem"
,
/* File name of client certificate file, optional */
"client_key.pem"
,
/* File name of client private key, optional */
"redis.mydomain.com"
,
/* Server name to request (SNI), optional */
&
ssl_error
)
!=
REDIS_OK
)
{
printf
(
"SSL error: %s
\n
"
,
redisSSLContextGetError
(
ssl_error
);
/* Abort... */
}
/* Create Redis context and establish connection */
c
=
redisConnect
(
"localhost"
,
6443
);
if
(
c
==
NULL
||
c
->
err
)
{
/* Handle error and abort... */
}
if
(
redisSecureConnection
(
c
,
"cacertbundle.crt"
,
/* File name of trusted CA/ca bundle file */
"client_cert.pem"
,
/* File name of client certificate file */
"client_key.pem"
,
/* File name of client private key */
"redis.mydomain.com"
/* Server name to request (SNI) */
)
!=
REDIS_OK
)
{
printf
(
"SSL error: %s
\n
"
,
c
->
errstr
);
/* Abort... */
/* Negotiate SSL/TLS */
if
(
redisInitiateSSLWithContext
(
c
,
ssl
)
!=
REDIS_OK
)
{
/* Handle error, in c->err / c->errstr */
}
```
You will also need to link against
`libhiredis_ssl`
,
**in addition**
to
`libhiredis`
and add
`-lssl -lcrypto`
to satisfy its dependencies.
### OpenSSL Global State Initialization
OpenSSL needs to have certain global state initialized before it can be used.
Using
`redisSecureConnection()`
will handle this automatically on the first
call.
**
If the calling application itself also initializes and uses OpenSSL directly,
`redisSecureConnection()`
must not be used.
**
Instead, use
`redisInitiateSSL()`
which also provides greater control over the
configuration of the SSL connection, as the caller is responsible to create a
connection context using
`SSL_new()`
and configure it as required.
## AUTHORS
Hiredis was written by Salvatore Sanfilippo (antirez at gmail) and
...
...
examples/example-libevent-ssl.c
View file @
190bca88
...
...
@@ -52,13 +52,25 @@ int main (int argc, char **argv) {
const
char
*
certKey
=
argv
[
5
];
const
char
*
caCert
=
argc
>
5
?
argv
[
6
]
:
NULL
;
redisSSLContext
*
ssl
;
redisSSLContextError
ssl_error
;
redisInitOpenSSL
();
ssl
=
redisCreateSSLContext
(
caCert
,
NULL
,
cert
,
certKey
,
NULL
,
&
ssl_error
);
if
(
!
ssl
)
{
printf
(
"Error: %s
\n
"
,
redisSSLContextGetError
(
ssl_error
));
return
1
;
}
redisAsyncContext
*
c
=
redisAsyncConnect
(
hostname
,
port
);
if
(
c
->
err
)
{
/* Let *c leak for now... */
printf
(
"Error: %s
\n
"
,
c
->
errstr
);
return
1
;
}
if
(
redis
SecureConnection
(
&
c
->
c
,
caCert
,
cert
,
certKey
,
"sni"
)
!=
REDIS_OK
)
{
if
(
redis
InitiateSSLWithContext
(
&
c
->
c
,
ssl
)
!=
REDIS_OK
)
{
printf
(
"SSL Error!
\n
"
);
exit
(
1
);
}
...
...
@@ -69,5 +81,7 @@ int main (int argc, char **argv) {
redisAsyncCommand
(
c
,
NULL
,
NULL
,
"SET key %b"
,
value
,
nvalue
);
redisAsyncCommand
(
c
,
getCallback
,
(
char
*
)
"end-1"
,
"GET key"
);
event_base_dispatch
(
base
);
redisFreeSSLContext
(
ssl
);
return
0
;
}
examples/example-ssl.c
View file @
190bca88
...
...
@@ -7,6 +7,8 @@
int
main
(
int
argc
,
char
**
argv
)
{
unsigned
int
j
;
redisSSLContext
*
ssl
;
redisSSLContextError
ssl_error
;
redisContext
*
c
;
redisReply
*
reply
;
if
(
argc
<
4
)
{
...
...
@@ -19,6 +21,14 @@ int main(int argc, char **argv) {
const
char
*
key
=
argv
[
4
];
const
char
*
ca
=
argc
>
4
?
argv
[
5
]
:
NULL
;
redisInitOpenSSL
();
ssl
=
redisCreateSSLContext
(
ca
,
NULL
,
cert
,
key
,
NULL
,
&
ssl_error
);
if
(
!
ssl
)
{
printf
(
"SSL Context error: %s
\n
"
,
redisSSLContextGetError
(
ssl_error
));
exit
(
1
);
}
struct
timeval
tv
=
{
1
,
500000
};
// 1.5 seconds
redisOptions
options
=
{
0
};
REDIS_OPTIONS_SET_TCP
(
&
options
,
hostname
,
port
);
...
...
@@ -35,7 +45,7 @@ int main(int argc, char **argv) {
exit
(
1
);
}
if
(
redis
SecureConnection
(
c
,
ca
,
cert
,
key
,
"sni"
)
!=
REDIS_OK
)
{
if
(
redis
InitiateSSLWithContext
(
c
,
ssl
)
!=
REDIS_OK
)
{
printf
(
"Couldn't initialize SSL!
\n
"
);
printf
(
"Error: %s
\n
"
,
c
->
errstr
);
redisFree
(
c
);
...
...
@@ -93,5 +103,7 @@ int main(int argc, char **argv) {
/* Disconnects and frees the context */
redisFree
(
c
);
redisFreeSSLContext
(
ssl
);
return
0
;
}
hiredis_ssl.h
View file @
190bca88
...
...
@@ -41,15 +41,81 @@ extern "C" {
*/
struct
ssl_st
;
/* A wrapper around OpenSSL SSL_CTX to allow easy SSL use without directly
* calling OpenSSL.
*/
typedef
struct
redisSSLContext
redisSSLContext
;
/**
* Initialization errors that redisCreateSSLContext() may return.
*/
typedef
enum
{
REDIS_SSL_CTX_NONE
=
0
,
/* No Error */
REDIS_SSL_CTX_CREATE_FAILED
,
/* Failed to create OpenSSL SSL_CTX */
REDIS_SSL_CTX_CERT_KEY_REQUIRED
,
/* Client cert and key must both be specified or skipped */
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED
,
/* Failed to load CA Certificate or CA Path */
REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED
,
/* Failed to load client certificate */
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED
/* Failed to load private key */
}
redisSSLContextError
;
/**
* Return the error message corresponding with the specified error code.
*/
const
char
*
redisSSLContextGetError
(
redisSSLContextError
error
);
/**
* Helper function to initialize the OpenSSL library.
*
* OpenSSL requires one-time initialization before it can be used. Callers should
* call this function only once, and only if OpenSSL is not directly initialized
* elsewhere.
*/
int
redisInitOpenSSL
(
void
);
/**
* Secure the connection using SSL. This should be done before any command is
* executed on the connection.
* Helper function to initialize an OpenSSL context that can be used
* to initiate SSL connections.
*
* cacert_filename is an optional name of a CA certificate/bundle file to load
* and use for validation.
*
* capath is an optional directory path where trusted CA certificate files are
* stored in an OpenSSL-compatible structure.
*
* cert_filename and private_key_filename are optional names of a client side
* certificate and private key files to use for authentication. They need to
* be both specified or omitted.
*
* server_name is an optional and will be used as a server name indication
* (SNI) TLS extension.
*
* If error is non-null, it will be populated in case the context creation fails
* (returning a NULL).
*/
redisSSLContext
*
redisCreateSSLContext
(
const
char
*
cacert_filename
,
const
char
*
capath
,
const
char
*
cert_filename
,
const
char
*
private_key_filename
,
const
char
*
server_name
,
redisSSLContextError
*
error
);
/**
* Free a previously created OpenSSL context.
*/
int
redisSecureConnection
(
redisContext
*
c
,
const
char
*
capath
,
const
char
*
certpath
,
const
char
*
keypath
,
const
char
*
servername
);
void
redisFreeSSLContext
(
redisSSLContext
*
redis_ssl_ctx
);
/**
* Initiate SSL on an existing redisContext.
*
* This is similar to redisInitiateSSL() but does not require the caller
* to directly interact with OpenSSL, and instead uses a redisSSLContext
* previously created using redisCreateSSLContext().
*/
int
redisInitiateSSLWithContext
(
redisContext
*
c
,
redisSSLContext
*
redis_ssl_ctx
);
/**
* Initiate SSL/TLS negotiation on a provided
contex
t.
* Initiate SSL/TLS negotiation on a provided
OpenSSL SSL objec
t.
*/
int
redisInitiateSSL
(
redisContext
*
c
,
struct
ssl_st
*
ssl
);
...
...
ssl.c
View file @
190bca88
...
...
@@ -47,17 +47,20 @@
#include "win32.h"
#include "async_private.h"
#include "hiredis_ssl.h"
void
__redisSetError
(
redisContext
*
c
,
int
type
,
const
char
*
str
);
/* The SSL context is attached to SSL/TLS connections as a privdata. */
typedef
struct
redisSSLContext
{
/**
* OpenSSL SSL_CTX; It is optional and will not be set when using
* user-supplied SSL.
*/
struct
redisSSLContext
{
/* Associated OpenSSL SSL_CTX as created by redisCreateSSLContext() */
SSL_CTX
*
ssl_ctx
;
/* Requested SNI, or NULL */
char
*
server_name
;
};
/* The SSL connection context is attached to SSL/TLS connections as a privdata. */
typedef
struct
redisSSL
{
/**
* OpenSSL SSL object.
*/
...
...
@@ -77,43 +80,11 @@ typedef struct redisSSLContext {
* should resume whenever a read takes place, if possible
*/
int
pendingWrite
;
}
redisSSL
Context
;
}
redisSSL
;
/* Forward declaration */
redisContextFuncs
redisContextSSLFuncs
;
#ifdef HIREDIS_SSL_TRACE
/**
* Callback used for debugging
*/
static
void
sslLogCallback
(
const
SSL
*
ssl
,
int
where
,
int
ret
)
{
const
char
*
retstr
;
int
should_log
=
0
;
/* Ignore low-level SSL stuff */
if
(
where
&
SSL_CB_ALERT
)
{
should_log
=
1
;
}
if
(
where
==
SSL_CB_HANDSHAKE_START
||
where
==
SSL_CB_HANDSHAKE_DONE
)
{
should_log
=
1
;
}
if
((
where
&
SSL_CB_EXIT
)
&&
ret
==
0
)
{
should_log
=
1
;
}
if
(
!
should_log
)
{
return
;
}
retstr
=
SSL_alert_type_string
(
ret
);
printf
(
"ST(0x%x). %s. R(0x%x)%s
\n
"
,
where
,
SSL_state_string_long
(
ssl
),
ret
,
retstr
);
if
(
where
==
SSL_CB_HANDSHAKE_DONE
)
{
printf
(
"Using SSL version %s. Cipher=%s
\n
"
,
SSL_get_version
(
ssl
),
SSL_get_cipher_name
(
ssl
));
}
}
#endif
/**
* OpenSSL global initialization and locking handling callbacks.
* Note that this is only required for OpenSSL < 1.1.0.
...
...
@@ -182,26 +153,130 @@ static int initOpensslLocks(void) {
}
#endif
/* HIREDIS_USE_CRYPTO_LOCKS */
int
redisInitOpenSSL
(
void
)
{
SSL_library_init
();
#ifdef HIREDIS_USE_CRYPTO_LOCKS
initOpensslLocks
();
#endif
return
REDIS_OK
;
}
/**
* redisSSLContext helper context destruction.
*/
const
char
*
redisSSLContextGetError
(
redisSSLContextError
error
)
{
switch
(
error
)
{
case
REDIS_SSL_CTX_NONE
:
return
"No Error"
;
case
REDIS_SSL_CTX_CREATE_FAILED
:
return
"Failed to create OpenSSL SSL_CTX"
;
case
REDIS_SSL_CTX_CERT_KEY_REQUIRED
:
return
"Client cert and key must both be specified or skipped"
;
case
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED
:
return
"Failed to load CA Certificate or CA Path"
;
case
REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED
:
return
"Failed to load client certificate"
;
case
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED
:
return
"Failed to load private key"
;
default:
return
"Unknown error code"
;
}
}
void
redisFreeSSLContext
(
redisSSLContext
*
ctx
)
{
if
(
!
ctx
)
return
;
if
(
ctx
->
server_name
)
{
hi_free
(
ctx
->
server_name
);
ctx
->
server_name
=
NULL
;
}
if
(
ctx
->
ssl_ctx
)
{
SSL_CTX_free
(
ctx
->
ssl_ctx
);
ctx
->
ssl_ctx
=
NULL
;
}
hi_free
(
ctx
);
}
/**
* redisSSLContext helper context initialization.
*/
redisSSLContext
*
redisCreateSSLContext
(
const
char
*
cacert_filename
,
const
char
*
capath
,
const
char
*
cert_filename
,
const
char
*
private_key_filename
,
const
char
*
server_name
,
redisSSLContextError
*
error
)
{
redisSSLContext
*
ctx
=
hi_calloc
(
1
,
sizeof
(
redisSSLContext
));
ctx
->
ssl_ctx
=
SSL_CTX_new
(
SSLv23_client_method
());
if
(
!
ctx
->
ssl_ctx
)
{
if
(
error
)
*
error
=
REDIS_SSL_CTX_CREATE_FAILED
;
goto
error
;
}
SSL_CTX_set_options
(
ctx
->
ssl_ctx
,
SSL_OP_NO_SSLv2
|
SSL_OP_NO_SSLv3
);
SSL_CTX_set_verify
(
ctx
->
ssl_ctx
,
SSL_VERIFY_PEER
,
NULL
);
if
((
cert_filename
!=
NULL
&&
private_key_filename
==
NULL
)
||
(
private_key_filename
!=
NULL
&&
cert_filename
==
NULL
))
{
if
(
error
)
*
error
=
REDIS_SSL_CTX_CERT_KEY_REQUIRED
;
goto
error
;
}
if
(
capath
||
cacert_filename
)
{
if
(
!
SSL_CTX_load_verify_locations
(
ctx
->
ssl_ctx
,
cacert_filename
,
capath
))
{
if
(
error
)
*
error
=
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED
;
goto
error
;
}
}
if
(
cert_filename
)
{
if
(
!
SSL_CTX_use_certificate_chain_file
(
ctx
->
ssl_ctx
,
cert_filename
))
{
if
(
error
)
*
error
=
REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED
;
goto
error
;
}
if
(
!
SSL_CTX_use_PrivateKey_file
(
ctx
->
ssl_ctx
,
private_key_filename
,
SSL_FILETYPE_PEM
))
{
if
(
error
)
*
error
=
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED
;
goto
error
;
}
}
if
(
server_name
)
ctx
->
server_name
=
hi_strdup
(
server_name
);
return
ctx
;
error:
redisFreeSSLContext
(
ctx
);
return
NULL
;
}
/**
* SSL Connection initialization.
*/
static
int
redisSSLConnect
(
redisContext
*
c
,
SSL_CTX
*
ssl_ctx
,
SSL
*
ssl
)
{
redisSSLContext
*
rssl
;
static
int
redisSSLConnect
(
redisContext
*
c
,
SSL
*
ssl
)
{
if
(
c
->
privdata
)
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"redisContext was already associated"
);
return
REDIS_ERR
;
}
rssl
=
hi_calloc
(
1
,
sizeof
(
redisSSL
Context
));
redisSSL
*
rssl
=
hi_calloc
(
1
,
sizeof
(
redisSSL
));
if
(
rssl
==
NULL
)
{
__redisSetError
(
c
,
REDIS_ERR_OOM
,
"Out of memory"
);
return
REDIS_ERR
;
}
c
->
funcs
=
&
redisContextSSLFuncs
;
rssl
->
ssl_ctx
=
ssl_ctx
;
rssl
->
ssl
=
ssl
;
SSL_set_mode
(
rssl
->
ssl
,
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER
);
...
...
@@ -238,84 +313,53 @@ static int redisSSLConnect(redisContext *c, SSL_CTX *ssl_ctx, SSL *ssl) {
return
REDIS_ERR
;
}
/**
* A wrapper around redisSSLConnect() for users who manage their own context and
* create their own SSL object.
*/
int
redisInitiateSSL
(
redisContext
*
c
,
SSL
*
ssl
)
{
return
redisSSLConnect
(
c
,
NULL
,
ssl
);
return
redisSSLConnect
(
c
,
ssl
);
}
int
redisSecureConnection
(
redisContext
*
c
,
const
char
*
capath
,
const
char
*
certpath
,
const
char
*
keypath
,
const
char
*
servername
)
{
SSL_CTX
*
ssl_ctx
=
NULL
;
SSL
*
ssl
=
NULL
;
/* Initialize global OpenSSL stuff */
static
int
isInit
=
0
;
if
(
!
isInit
)
{
isInit
=
1
;
SSL_library_init
();
#ifdef HIREDIS_USE_CRYPTO_LOCKS
if
(
initOpensslLocks
()
==
REDIS_ERR
)
{
__redisSetError
(
c
,
REDIS_ERR_OOM
,
"Out of memory"
);
goto
error
;
}
#endif
}
ssl_ctx
=
SSL_CTX_new
(
SSLv23_client_method
());
if
(
!
ssl_ctx
)
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"Failed to create SSL_CTX"
);
goto
error
;
}
/**
* A wrapper around redisSSLConnect() for users who use redisSSLContext and don't
* manage their own SSL objects.
*/
#ifdef HIREDIS_SSL_TRACE
SSL_CTX_set_info_callback
(
ssl_ctx
,
sslLogCallback
);
#endif
SSL_CTX_set_options
(
ssl_ctx
,
SSL_OP_NO_SSLv2
|
SSL_OP_NO_SSLv3
);
SSL_CTX_set_verify
(
ssl_ctx
,
SSL_VERIFY_PEER
,
NULL
);
if
((
certpath
!=
NULL
&&
keypath
==
NULL
)
||
(
keypath
!=
NULL
&&
certpath
==
NULL
))
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"certpath and keypath must be specified together"
);
goto
error
;
}
int
redisInitiateSSLWithContext
(
redisContext
*
c
,
redisSSLContext
*
redis_ssl_ctx
)
{
if
(
!
c
||
!
redis_ssl_ctx
)
return
REDIS_ERR
;
if
(
capath
)
{
if
(
!
SSL_CTX_load_verify_locations
(
ssl_ctx
,
capath
,
NULL
))
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"Invalid CA certificate"
);
goto
error
;
}
}
if
(
certpath
)
{
if
(
!
SSL_CTX_use_certificate_chain_file
(
ssl_ctx
,
certpath
))
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"Invalid client certificate"
);
goto
error
;
}
if
(
!
SSL_CTX_use_PrivateKey_file
(
ssl_ctx
,
keypath
,
SSL_FILETYPE_PEM
))
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"Invalid client key"
);
goto
error
;
}
}
/* We want to verify that redisSSLConnect() won't fail on this, as it will
* not own the SSL object in that case and we'll end up leaking.
*/
if
(
c
->
privdata
)
return
REDIS_ERR
;
ssl
=
SSL_new
(
ssl_ctx
);
SSL
*
ssl
=
SSL_new
(
redis_ssl_ctx
->
ssl_ctx
);
if
(
!
ssl
)
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"Couldn't create new SSL instance"
);
goto
error
;
}
if
(
servername
)
{
if
(
!
SSL_set_tlsext_host_name
(
ssl
,
servername
))
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"Couldn't set server name indication"
);
if
(
redis_ssl_ctx
->
server_name
)
{
if
(
!
SSL_set_tlsext_host_name
(
ssl
,
redis_ssl_ctx
->
server_name
))
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"Failed to set server_name/SNI"
);
goto
error
;
}
}
if
(
redisSSLConnect
(
c
,
ssl_ctx
,
ssl
)
==
REDIS_OK
)
return
REDIS_OK
;
return
redisSSLConnect
(
c
,
ssl
);
error:
if
(
ssl
)
SSL_free
(
ssl
);
if
(
ssl_ctx
)
SSL_
CTX_
free
(
ssl
_ctx
);
if
(
ssl
)
SSL_free
(
ssl
);
return
REDIS_ERR
;
}
static
int
maybeCheckWant
(
redisSSL
Context
*
rssl
,
int
rv
)
{
static
int
maybeCheckWant
(
redisSSL
*
rssl
,
int
rv
)
{
/**
* If the error is WANT_READ or WANT_WRITE, the appropriate flags are set
* and true is returned. False is returned otherwise
...
...
@@ -335,23 +379,19 @@ static int maybeCheckWant(redisSSLContext *rssl, int rv) {
* Implementation of redisContextFuncs for SSL connections.
*/
static
void
redisSSLFree
Context
(
void
*
privdata
){
redisSSL
Context
*
rsc
=
privdata
;
static
void
redisSSLFree
(
void
*
privdata
){
redisSSL
*
rsc
=
privdata
;
if
(
!
rsc
)
return
;
if
(
rsc
->
ssl
)
{
SSL_free
(
rsc
->
ssl
);
rsc
->
ssl
=
NULL
;
}
if
(
rsc
->
ssl_ctx
)
{
SSL_CTX_free
(
rsc
->
ssl_ctx
);
rsc
->
ssl_ctx
=
NULL
;
}
hi_free
(
rsc
);
}
static
int
redisSSLRead
(
redisContext
*
c
,
char
*
buf
,
size_t
bufcap
)
{
redisSSL
Context
*
rssl
=
c
->
privdata
;
redisSSL
*
rssl
=
c
->
privdata
;
int
nread
=
SSL_read
(
rssl
->
ssl
,
buf
,
bufcap
);
if
(
nread
>
0
)
{
...
...
@@ -393,7 +433,7 @@ static int redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
}
static
int
redisSSLWrite
(
redisContext
*
c
)
{
redisSSL
Context
*
rssl
=
c
->
privdata
;
redisSSL
*
rssl
=
c
->
privdata
;
size_t
len
=
rssl
->
lastLen
?
rssl
->
lastLen
:
sdslen
(
c
->
obuf
);
int
rv
=
SSL_write
(
rssl
->
ssl
,
c
->
obuf
,
len
);
...
...
@@ -416,7 +456,7 @@ static int redisSSLWrite(redisContext *c) {
static
void
redisSSLAsyncRead
(
redisAsyncContext
*
ac
)
{
int
rv
;
redisSSL
Context
*
rssl
=
ac
->
c
.
privdata
;
redisSSL
*
rssl
=
ac
->
c
.
privdata
;
redisContext
*
c
=
&
ac
->
c
;
rssl
->
wantRead
=
0
;
...
...
@@ -446,7 +486,7 @@ static void redisSSLAsyncRead(redisAsyncContext *ac) {
static
void
redisSSLAsyncWrite
(
redisAsyncContext
*
ac
)
{
int
rv
,
done
=
0
;
redisSSL
Context
*
rssl
=
ac
->
c
.
privdata
;
redisSSL
*
rssl
=
ac
->
c
.
privdata
;
redisContext
*
c
=
&
ac
->
c
;
rssl
->
pendingWrite
=
0
;
...
...
@@ -475,7 +515,7 @@ static void redisSSLAsyncWrite(redisAsyncContext *ac) {
}
redisContextFuncs
redisContextSSLFuncs
=
{
.
free_privdata
=
redisSSLFree
Context
,
.
free_privdata
=
redisSSLFree
,
.
async_read
=
redisSSLAsyncRead
,
.
async_write
=
redisSSLAsyncWrite
,
.
read
=
redisSSLRead
,
...
...
test.c
View file @
190bca88
...
...
@@ -48,6 +48,10 @@ struct config {
}
ssl
;
};
#ifdef HIREDIS_TEST_SSL
redisSSLContext
*
_ssl_ctx
=
NULL
;
#endif
/* The following lines make up our testing "framework" :) */
static
int
tests
=
0
,
fails
=
0
,
skips
=
0
;
#define test(_s) { printf("#%02d ", ++tests); printf(_s); }
...
...
@@ -113,9 +117,9 @@ static int disconnect(redisContext *c, int keep_fd) {
return
-
1
;
}
static
void
do_ssl_handshake
(
redisContext
*
c
,
struct
config
config
)
{
static
void
do_ssl_handshake
(
redisContext
*
c
)
{
#ifdef HIREDIS_TEST_SSL
redis
SecureConnection
(
c
,
config
.
ssl
.
ca_cert
,
config
.
ssl
.
cert
,
config
.
ssl
.
key
,
NULL
);
redis
InitiateSSLWithContext
(
c
,
_ssl_ctx
);
if
(
c
->
err
)
{
printf
(
"SSL error: %s
\n
"
,
c
->
errstr
);
redisFree
(
c
);
...
...
@@ -123,7 +127,6 @@ static void do_ssl_handshake(redisContext *c, struct config config) {
}
#else
(
void
)
c
;
(
void
)
config
;
#endif
}
...
...
@@ -158,7 +161,7 @@ static redisContext *do_connect(struct config config) {
}
if
(
config
.
type
==
CONN_SSL
)
{
do_ssl_handshake
(
c
,
config
);
do_ssl_handshake
(
c
);
}
return
select_database
(
c
);
...
...
@@ -168,7 +171,7 @@ static void do_reconnect(redisContext *c, struct config config) {
redisReconnect
(
c
);
if
(
config
.
type
==
CONN_SSL
)
{
do_ssl_handshake
(
c
,
config
);
do_ssl_handshake
(
c
);
}
}
...
...
@@ -1147,6 +1150,11 @@ int main(int argc, char **argv) {
#ifdef HIREDIS_TEST_SSL
if
(
cfg
.
ssl
.
port
&&
cfg
.
ssl
.
host
)
{
redisInitOpenSSL
();
_ssl_ctx
=
redisCreateSSLContext
(
cfg
.
ssl
.
ca_cert
,
NULL
,
cfg
.
ssl
.
cert
,
cfg
.
ssl
.
key
,
NULL
,
NULL
);
assert
(
_ssl_ctx
!=
NULL
);
printf
(
"
\n
Testing against SSL connection (%s:%d):
\n
"
,
cfg
.
ssl
.
host
,
cfg
.
ssl
.
port
);
cfg
.
type
=
CONN_SSL
;
...
...
@@ -1156,6 +1164,9 @@ int main(int argc, char **argv) {
test_invalid_timeout_errors
(
cfg
);
test_append_formatted_commands
(
cfg
);
if
(
throughput
)
test_throughput
(
cfg
);
redisFreeSSLContext
(
_ssl_ctx
);
_ssl_ctx
=
NULL
;
}
#endif
...
...
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