Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
hiredis
Commits
4152bfce
Commit
4152bfce
authored
May 30, 2020
by
michael-grunder
Browse files
Merge branch 'new-ssl-api'
parents
e553e0f3
904bf7fe
Changes
6
Hide whitespace changes
Inline
Side-by-side
README.md
View file @
4152bfce
...
...
@@ -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.
## Allocator injection
Hiredis uses a pass-thru structure of function pointers defined in
...
...
examples/example-libevent-ssl.c
View file @
4152bfce
...
...
@@ -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 @
4152bfce
...
...
@@ -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 @
4152bfce
...
...
@@ -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 @
4152bfce
...
...
@@ -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,132 @@ 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
));
if
(
ctx
==
NULL
)
goto
error
;
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 +315,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 +381,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 +435,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 +458,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 +488,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 +517,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 @
4152bfce
...
...
@@ -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
);
}
}
...
...
@@ -1148,6 +1151,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
;
...
...
@@ -1157,6 +1165,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