SSL作为OPENSSL一个关键数据结构一点都不过分,无论是在SSL初始化连接,还是在读写数据,SSL数据结构都起着重要作用。SSL这个数据结构将SSL协议复杂的连接过程都封装在内部,提供一个简单的接口让用户调用,就象调用WINSOCK的连接函数一样简单。掌握OPENSSL,了解SSL内部结构非常必要。
SSL的数据结构
struct ssl_st
{
/* protocol version
* (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION)
*/
int version;
int type; /* SSL_ST_CONNECT or SSL_ST_ACCEPT */
SSL_METHOD *method; /* SSLv3 */
/* There are 2 BIO's even though they are normally both the
* same. This is so data can be read and written to different
* handlers */
#ifndef OPENSSL_NO_BIO
BIO *rbio; /* used by SSL_read */
BIO *wbio; /* used by SSL_write */
BIO *bbio; /* used during session-id reuse to concatenate
* messages */
#else
char *rbio; /* used by SSL_read */
char *wbio; /* used by SSL_write */
char *bbio;
#endif
/* This holds a variable that indicates what we were doing
* when a 0 or -1 is returned. This is needed for
* non-blocking IO so we know what request needs re-doing when
* in SSL_accept or SSL_connect */
int rwstate;
/* true when we are actually in SSL_accept() or SSL_connect() */
int in_handshake;
int (*handshake_func)();
/* Imagine that here's a boolean member "init" that is
* switched as soon as SSL_set_{accept/connect}_state
* is called for the first time, so that "state" and
* "handshake_func" are properly initialized. But as
* handshake_func is == 0 until then, we use this
* test instead of an "init" member.
*/
int server; /* are we the server side? - mostly used by SSL_clear*/
int new_session;/* 1 if we are to use a new session.
* 2 if we are a server and are inside a handshake
* (i.e. not just sending a HelloRequest)
* NB: For servers, the 'new' session may actually be a previously
* cached session or even the previous session unless
* SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */
int quiet_shutdown;/* don't send shutdown packets */
int shutdown; /* we have shut things down, 0x01 sent, 0x02
* for received */
int state; /* where we are */
int rstate; /* where we are when reading */
BUF_MEM *init_buf; /* buffer used during init */
void *init_msg; /* pointer to handshake message body, set by ssl3_get_message() */
int init_num; /* amount read/written */
int init_off; /* amount read/written */
/* used internally to point at a raw packet */
unsigned char *packet;
unsigned int packet_length;
struct ssl2_state_st *s2; /* SSLv2 variables */
struct ssl3_state_st *s3; /* SSLv3 variables */
int read_ahead; /* Read as many input bytes as possible
* (for non-blocking reads) */
/* callback that allows applications to peek at protocol messages */
void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
void *msg_callback_arg;
int hit; /* reusing a previous session */
int purpose; /* Purpose setting */
int trust; /* Trust setting */
/* crypto */
STACK_OF(SSL_CIPHER) *cipher_list;
STACK_OF(SSL_CIPHER) *cipher_list_by_id;
/* These are the ones being used, the ones in SSL_SESSION are
* the ones to be 'copied' into these ones */
EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */
const EVP_MD *read_hash; /* used for mac generation */
#ifndef OPENSSL_NO_COMP
COMP_CTX *expand; /* uncompress */
#else
char *expand;
#endif
EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */
const EVP_MD *write_hash; /* used for mac generation */
#ifndef OPENSSL_NO_COMP
COMP_CTX *compress; /* compression */
#else
char *compress;
#endif
/* session info */
/* client cert? */
/* This is used to hold the server certificate used */
struct cert_st /* CERT */ *cert;
/* the session_id_context is used to ensure sessions are only reused
* in the appropriate context */
unsigned int sid_ctx_length;
unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
/* This can also be in the session once a session is established */
SSL_SESSION *session;
/* Default generate session ID callback. */
GEN_SESSION_CB generate_session_id;
/* Used in SSL2 and SSL3 */
int verify_mode; /* 0 don't care about verify failure.
* 1 fail if verify fails */
int verify_depth;
int (*verify_callback)(int ok,X509_STORE_CTX *ctx); /* fail if callback returns 0 */
void (*info_callback)(const SSL *ssl,int type,int val); /* optional informational callback */
int error; /* error bytes to be written */
int error_code; /* actual code */
#ifndef OPENSSL_NO_KRB5
KSSL_CTX *kssl_ctx; /* Kerberos 5 context */
#endif /* OPENSSL_NO_KRB5 */
SSL_CTX *ctx;
/* set this flag to 1 and a sleep(1) is put into all SSL_read()
* and SSL_write() calls, good for nbio debuging :-) */
int debug;
/* extra application data */
long verify_result;
CRYPTO_EX_DATA ex_data;
/* for server side, keep the list of CA_dn we can use */
STACK_OF(X509_NAME) *client_CA;
int references;
unsigned long options; /* protocol behaviour */
unsigned long mode; /* API behaviour */
long max_cert_list;
int first_packet;
int client_version; /* what was passed, used for
* SSLv3/TLS rollback check */
};
★SSL的函数
#include
int SSL_accept(SSL *s)
{
if (s->handshake_func == 0)
/* Not properly initialized yet */
SSL_set_accept_state(s);
return(s->method->ssl_accept(s));
}
int SSL_check_private_key(const SSL *ssl)
{
if (ssl == NULL)
{
SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,ERR_R_PASSED_NULL_PARAMETER);
return(0);
}
if (ssl->cert == NULL)
{
SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,SSL_R_NO_CERTIFICATE_ASSIGNED);
return 0;
}
if (ssl->cert->key->x509 == NULL)
{
SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,SSL_R_NO_CERTIFICATE_ASSIGNED);
return(0);
}
if (ssl->cert->key->privatekey == NULL)
{
SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY,SSL_R_NO_PRIVATE_KEY_ASSIGNED);
return(0);
}
return(X509_check_private_key(ssl->cert->key->x509,
ssl->cert->key->privatekey));
}
int SSL_read(SSL *s,void *buf,int num)
{
if (s->handshake_func == 0)
{
SSLerr(SSL_F_SSL_READ, SSL_R_UNINITIALIZED);
return -1;
}
if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
{
s->rwstate=SSL_NOTHING;
return(0);
}
return(s->method->ssl_read(s,buf,num));
}
int SSL_write(SSL *s,const void *buf,int num)
{
if (s->handshake_func == 0)
{
SSLerr(SSL_F_SSL_WRITE, SSL_R_UNINITIALIZED);
return -1;
}
if (s->shutdown & SSL_SENT_SHUTDOWN)
{
s->rwstate=SSL_NOTHING;
SSLerr(SSL_F_SSL_WRITE,SSL_R_PROTOCOL_IS_SHUTDOWN);
return(-1);
}
return(s->method->ssl_write(s,buf,num));
}
int SSL_shutdown(SSL *s)
{
/* Note that this function behaves differently from what one might
* expect. Return values are 0 for no success (yet),
* 1 for success; but calling it once is usually not enough,
* even if blocking I/O is used (see ssl3_shutdown).
*/
if (s->handshake_func == 0)
{
SSLerr(SSL_F_SSL_SHUTDOWN, SSL_R_UNINITIALIZED);
return -1;
}
if ((s != NULL) && !SSL_in_init(s))
return(s->method->ssl_shutdown(s));
else
return(1);
}
long SSL_ctrl(SSL *s,int cmd,long larg,void *parg)
{
long l;
switch (cmd)
{
case SSL_CTRL_GET_READ_AHEAD:
return(s->read_ahead);
case SSL_CTRL_SET_READ_AHEAD:
l=s->read_ahead;
s->read_ahead=larg;
return(l);
case SSL_CTRL_SET_MSG_CALLBACK_ARG:
s->msg_callback_arg = parg;
return 1;
case SSL_CTRL_OPTIONS:
return(s->options|=larg);
case SSL_CTRL_MODE:
return(s->mode|=larg);
case SSL_CTRL_GET_MAX_CERT_LIST:
return(s->max_cert_list);
case SSL_CTRL_SET_MAX_CERT_LIST:
l=s->max_cert_list;
s->max_cert_list=larg;
return(l);
default:
return(s->method->ssl_ctrl(s,cmd,larg,parg));
}
}
long SSL_callback_ctrl(SSL *s, int cmd, void (*fp)())
{
switch(cmd)
{
case SSL_CTRL_SET_MSG_CALLBACK:
s->msg_callback = (void (*)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg))(fp);
return 1;
default:
return(s->method->ssl_callback_ctrl(s,cmd,fp));
}
}
struct lhash_st *SSL_CTX_sessions(SSL_CTX *ctx)
{
return ctx->sessions;
}
int ssl_cipher_id_cmp(const SSL_CIPHER *a, const SSL_CIPHER *b)
{
long l;
l=a->id-b->id;
if (l == 0L )
return(0);
else
return((l > 0)?1:-1);
}
int ssl_cipher_ptr_id_cmp(const SSL_CIPHER * const *ap,
const SSL_CIPHER * const *bp)
{
long l;
l=(*ap)->id-(*bp)->id;
if (l == 0L )
return(0);
else
return((l > 0)?1:-1);
}
STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s)
{
if (s != NULL)
{
if (s->cipher_list != NULL)
{
return(s->cipher_list);
}
else if ((s->ctx != NULL) &&
(s->ctx->cipher_list != NULL))
{
return(s->ctx->cipher_list);
}
}
return(NULL);
}
/** return a STACK of the ciphers available for the SSL and in order of
* algorithm id */
STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s)
{
if (s != NULL)
{
if (s->cipher_list_by_id != NULL)
{
return(s->cipher_list_by_id);
}
else if ((s->ctx != NULL) &&
(s->ctx->cipher_list_by_id != NULL))
{
return(s->ctx->cipher_list_by_id);
}
}
return(NULL);
}
/** The old interface to get the same thing as SSL_get_ciphers() */
const char *SSL_get_cipher_list(const SSL *s,int n)
{
SSL_CIPHER *c;
STACK_OF(SSL_CIPHER) *sk;
if (s == NULL) return(NULL);
sk=SSL_get_ciphers(s);
if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= n))
return(NULL);
c=sk_SSL_CIPHER_value(sk,n);
if (c == NULL) return(NULL);
return(c->name);
}
int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str)
{
STACK_OF(SSL_CIPHER) *sk;
sk=ssl_create_cipher_list(ctx->method,&ctx->cipher_list,
&ctx->cipher_list_by_id,str);
/* XXXX */
return((sk == NULL)?0:1);
}
char *SSL_get_shared_ciphers(const SSL *s,char *buf,int len)
{
char *p;
const char *cp;
STACK_OF(SSL_CIPHER) *sk;
SSL_CIPHER *c;
int i;
if ((s->session == NULL) || (s->session->ciphers == NULL) ||
(len < 2))
return(NULL);
p=buf;
sk=s->session->ciphers;
for (i=0; i
{
/* Decrement for either the ':' or a '/0' */
len--;
c=sk_SSL_CIPHER_value(sk,i);
for (cp=c->name; *cp; )
{
if (len-- == 0)
{
*p='/0';
return(buf);
}
else
*(p++)= *(cp++);
}
*(p++)=':';
}
p[-1]='/0';
return(buf);
}
unsigned long SSL_SESSION_hash(const SSL_SESSION *a)
{
unsigned long l;
l=(unsigned long)
((unsigned int) a->session_id[0] )|
((unsigned int) a->session_id[1]<< 8L )|
((unsigned long)a->session_id[2]<< 16L )|
((unsigned long)a->session_id[3]<< 24L );
return(l);
}
int SSL_do_handshake(SSL *s)
{
int ret=1;
if (s->handshake_func == NULL)
{
SSLerr(SSL_F_SSL_DO_HANDSHAKE,SSL_R_CONNECTION_TYPE_NOT_SET);
return(-1);
}
s->method->ssl_renegotiate_check(s);
if (SSL_in_init(s) || SSL_in_before(s))
{
ret=s->handshake_func(s);
}
return(ret);
}
函数名: int SSL_do_handshake(SSL *ssl);
功能描述:SSL_do_handshake() will wait for a SSL/TLS handshake to take place. If the connection is in client mode, the handshake will be started. The handshake routines may have to be explicitly set in advance using either L
The behaviour of SSL_do_handshake() depends on the underlying BIO.
函数名 STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *ssl);
const char *SSL_get_cipher_list(const SSL *ssl, int priority);
功能描述:
SSL_get_ciphers() returns the stack of available SSL_CIPHERs for B
SSL_get_cipher_list() returns a pointer to the name of the SSL_CIPHER listed for B
函数名:
STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s);
STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx);
功能描述:
SSL_CTX_get_client_CA_list() returns the list of client CAs explicitly set for
B
SSL_get_client_CA_list() returns the list of client CAs explicitly set for B
L
server mode. In client mode, SSL_get_client_CA_list returns the list of
client CAs sent from the server, if any.
函数名:SSL_CIPHER *SSL_get_current_cipher(const SSL *ssl);
#define SSL_get_cipher(s) /
SSL_CIPHER_get_name(SSL_get_current_cipher(s))
#define SSL_get_cipher_name(s) /
SSL_CIPHER_get_name(SSL_get_current_cipher(s))
#define SSL_get_cipher_bits(s,np) /
SSL_CIPHER_get_bits(SSL_get_current_cipher(s),np)
#define SSL_get_cipher_version(s) /
SSL_CIPHER_get_version(SSL_get_current_cipher(s))
函数功能:SSL_get_current_cipher() returns a pointer to an SSL_CIPHER object containing
the description of the actually used cipher of a connection established with the B
SSL_get_cipher() and SSL_get_cipher_name() are identical macros to obtain the
name of the currently used cipher. SSL_get_cipher_bits() is a macro to obtain the number of secret/algorithm bits used and SSL_get_cipher_version() returns the protocol name.
See L
函数名:int SSL_get_error(const SSL *ssl, int ret);
函数功能:SSL_get_error() returns a result code (suitable for the C "switch"
statement) for a preceding call to SSL_connect(), SSL_accept(), SSL_do_handshake(),
SSL_read(), SSL_peek(), or SSL_write() on B
In addition to B
attempted, or SSL_get_error() will not work reliably.
函数名:int SSL_get_ex_data_X509_STORE_CTX_idx(void);
功能描述:SSL_get_ex_data_X509_STORE_CTX_idx() returns the index number under which
the pointer to the SSL object is stored into the X509_STORE_CTX object.
函数名:int SSL_get_ex_new_index(long argl, void *argp,
CRYPTO_EX_new *new_func,
CRYPTO_EX_dup *dup_func,
CRYPTO_EX_free *free_func);
int SSL_set_ex_data(SSL *ssl, int idx, void *arg);
void *SSL_get_ex_data(const SSL *ssl, int idx);
typedef int new_func(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
int idx, long argl, void *argp);
typedef void free_func(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
int idx, long argl, void *argp);
typedef int dup_func(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from, void *from_d,
int idx, long argl, void *argp);
功能描述:Several OpenSSL structures can have application specific data attached to them.
These functions are used internally by OpenSSL to manipulate application
specific data attached to a specific structure.
SSL_get_ex_new_index() is used to register a new index for application
specific data.
SSL_set_ex_data() is used to store application data at B
the B
SSL_get_ex_data() is used to retrieve the information for B
B
A detailed description for the B<*_get_ex_new_index()> functionality
can be found in L
The B<*_get_ex_data()> and B<*_set_ex_data()> functionality is described in
L
函数名:int SSL_get_fd(const SSL *ssl);
int SSL_get_rfd(const SSL *ssl);
int SSL_get_wfd(const SSL *ssl);
功能描述:SSL_get_fd() returns the file descriptor which is linked to B
SSL_get_rfd() and SSL_get_wfd() return the file descriptors for the
read or the write channel, which can be different. If the read and the
write channel are different, SSL_get_fd() will return the file descriptor
of the read channel.
函数名:STACKOF(X509) *SSL_get_peer_cert_chain(const SSL *ssl);
功能描述:SSL_get_peer_cert_chain() returns a pointer to STACKOF(X509) certificates
forming the certificate chain of the peer. If called on the client side,
the stack also contains the peer's certificate; if called on the server
side, the peer's certificate must be obtained separately using
L
If the peer did not present a certificate, NULL is returned.
函数名:X509 *SSL_get_peer_certificate(const SSL *ssl);
功能描述:SSL_get_peer_certificate() returns a pointer to the X509 certificate the
peer presented. If the peer did not present a certificate, NULL is returned.
函数名:BIO *SSL_get_rbio(SSL *ssl);
BIO *SSL_get_wbio(SSL *ssl);
功能描述:SSL_get_rbio() and SSL_get_wbio() return pointers to the BIOs for the
read or the write channel, which can be different. The reference count
of the BIO is not incremented.
函数名:SSL_SESSION *SSL_get_session(const SSL *ssl);
SSL_SESSION *SSL_get0_session(const SSL *ssl);
SSL_SESSION *SSL_get1_session(SSL *ssl);
功能描述:SSL_get_session() returns a pointer to the B
B
that the pointer can become invalid by other operations.
SSL_get0_session() is the same as SSL_get_session().
SSL_get1_session() is the same as SSL_get_session(), but the reference
count of the B
函数名:SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl);
功能描述:SSL_get_SSL_CTX() returns a pointer to the SSL_CTX object, from which
B
函数名:long SSL_get_verify_result(const SSL *ssl);
功能描述:SSL_get_verify_result() returns the result of the verification of the
X509 certificate presented by the peer, if any.
函数名:const char *SSL_get_version(const SSL *ssl);
功能描述:SSL_get_cipher_version() returns the name of the protocol used for the
connection B
函数名:SSL *SSL_new(SSL_CTX *ctx);
功能描述:SSL_new() creates a new B
data for a TLS/SSL connection. The new structure inherits the settings
of the underlying context B
options, verification settings, timeout settings.
函数名:SSL_read - read bytes from a TLS/SSL connection.
功能描述:SSL_read() tries to read B
buffer B
函数名:void SSL_SESSION_free(SSL_SESSION *session);
功能描述:SSL_SESSION_free() decrements the reference count of B
the B
memory, if the the reference count has reached 0.
函数名:long SSL_SESSION_get_time(const SSL_SESSION *s);
long SSL_SESSION_set_time(SSL_SESSION *s, long tm);
long SSL_SESSION_get_timeout(const SSL_SESSION *s);
long SSL_SESSION_set_timeout(SSL_SESSION *s, long tm);
long SSL_get_time(const SSL_SESSION *s);
long SSL_set_time(SSL_SESSION *s, long tm);
long SSL_get_timeout(const SSL_SESSION *s);
long SSL_set_timeout(SSL_SESSION *s, long tm);
功能描述:SSL_SESSION_get_time() returns the time at which the session B was
established. The time is given in seconds since the Epoch and therefore
compatible to the time delivered by the time() call.
SSL_SESSION_set_time() replaces the creation time of the session B with
the chosen value B
SSL_SESSION_get_timeout() returns the timeout value set for session B
in seconds.
SSL_SESSION_set_timeout() sets the timeout value for session B in seconds
to B
The SSL_get_time(), SSL_set_time(), SSL_get_timeout(), and SSL_set_timeout()
functions are synonyms for the SSL_SESSION_*() counterparts.
函数名:void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio);
功能描述:SSL_set_bio() connects the BIOs B
operations of the TLS/SSL (encrypted) side of B
The SSL engine inherits the behaviour of B
If a BIO is non-blocking, the B
If there was already a BIO connected to B
(for both the reading and writing side, if different).
函数名:void SSL_set_connect_state(SSL *ssl);
void SSL_set_accept_state(SSL *ssl);
功能描述:SSL_set_connect_state() sets B
SSL_set_accept_state() sets B
When the SSL_CTX object was created with L
it was either assigned a dedicated client method, a dedicated server
method, or a generic method, that can be used for both client and
server connections. (The method might have been changed with
L
SSL_set_ssl_method().)
When beginning a new handshake, the SSL engine must know whether it must
call the connect (client) or accept (server) routines. Even though it may
be clear from the method chosen, whether client or server mode was
requested, the handshake routines must be explicitly set.
When using the L
L
routines are automatically set. When performing a transparent negotiation
using L
handshake routines must be explicitly set in advance using either
SSL_set_connect_state() or SSL_set_accept_state().
函数名:int SSL_set_fd(SSL *ssl, int fd);
int SSL_set_rfd(SSL *ssl, int fd);
int SSL_set_wfd(SSL *ssl, int fd);
功能描述:SSL_set_fd() sets the file descriptor B
for the TLS/SSL (encrypted) side of B
socket file descriptor of a network connection.
When performing the operation, a B
interface between the B
inherit the behaviour of B
also have non-blocking behaviour.
If there was already a BIO connected to B
(for both the reading and writing side, if different).
SSL_set_rfd() and SSL_set_wfd() perform the respective action, but only
for the read channel or the write channel, which can be set independently.
函数名:int SSL_set_session(SSL *ssl, SSL_SESSION *session);
功能描述:SSL_set_session() sets B
is to be established. SSL_set_session() is only useful for TLS/SSL clients.
When the session is set, the reference count of B
by 1. If the session is not reused, the reference count is decremented
again during SSL_connect(). Whether the session was reused can be queried
with the L
If there is already a session set inside B
SSL_set_session() before or because the same B
a connection), SSL_SESSION_free() will be called for that session.
函数名:void SSL_set_shutdown(SSL *ssl, int mode);
int SSL_get_shutdown(const SSL *ssl);
功能描述:SSL_set_shutdown() sets the shutdown state of B
SSL_get_shutdown() returns the shutdown mode of B
函数名:void SSL_set_verify_result(SSL *ssl, long verify_result);
功能描述:SSL_set_verify_result() sets B
result of the verification of the X509 certificate presented by the peer,
if any.
函数名:int SSL_shutdown(SSL *ssl);
功能描述:SSL_shutdown() shuts down an active TLS/SSL connection. It sends the
"close notify" shutdown alert to the peer.
函数名:int SSL_want(const SSL *ssl);
int SSL_want_nothing(const SSL *ssl);
int SSL_want_read(const SSL *ssl);
int SSL_want_write(const SSL *ssl);
int SSL_want_x509_lookup(const SSL *ssl);
功能描述:SSL_want() returns state information for the SSL object B
The other SSL_want_*() calls are shortcuts for the possible states returned
by SSL_want().
函数名:int SSL_write(SSL *ssl, const void *buf, int num);
功能描述:SSL_write() writes B