OpenSSL的源代码包括三部分:加密算法库、SSL库和应用程序。
加密算法库的源代码主要在crypto文件夹里,包括ASN.1编码与解码接口(crypto/asn1/asn1.h),伪随机数产生器(crypto/rand/rand.h),ENGINE机制(crypto/engine),统一密码算法的EVP密码算法接口(crypto/evp/evp.h),大数运算接口(crypto/bn/bn.h),私钥信息语法(crypto/x509/x509.h),非对称密码算法(crypto/rsa/ras.h)等。
SSL库的源代码主要在ssl文件夹里,我们重点分析。
SSL相关的几个重要的数据结构包括:
1、SSL连接结构:核心结构,应用程序通过该结构获取所有其他结构。
2、上下文结构SSL_CTX:是全局的上下文结构,含有结构SSL的主要默认值,包含SSL会话结构。
3、会话结构SSL_SESSION:含有链接的当前TLS/SSL会话细节。
4、密码结构SSL_CIPHER:含有制定的加密算法信息。
5、方法结构SSL_METHOD:功能函数接口,统一了各种SSL协议版本(SSLv1, SSLv2, SSLv3, TLSv1)。
SSL连接结构列出如下:
struct ssl_st
{
/* protocol version
* (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, DTLS1_VERSION)
*/
int version;
int type; /* SSL_ST_CONNECT or SSL_ST_ACCEPT */
const 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)(SSL *);
/* 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 */
struct dtls1_state_st *d1; /* DTLSv1 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 */
X509_VERIFY_PARAM *param;
#if 0
int purpose; /* Purpose setting */
int trust; /* Trust setting */
#endif
/* 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 */
int mac_flags;
EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */
EVP_MD_CTX *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 */
EVP_MD_CTX *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_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 */
#ifndef OPENSSL_NO_PSK
unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, char *identity,
unsigned int max_identity_len, unsigned char *psk,
unsigned int max_psk_len);
unsigned int (*psk_server_callback)(SSL *ssl, const char *identity,
unsigned char *psk, unsigned int max_psk_len);
#endif
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 */
unsigned int max_send_fragment;
#ifndef OPENSSL_NO_TLSEXT
/* TLS extension debug callback */
void (*tlsext_debug_cb)(SSL *s, int client_server, int type,
unsigned char *data, int len,
void *arg);
void *tlsext_debug_arg;
char *tlsext_hostname;
int servername_done; /* no further mod of servername
0 : call the servername extension callback.
1 : prepare 2, allow last ack just after in server callback.
2 : don't call servername callback, no ack in server hello
*/
/* certificate status request info */
/* Status type or -1 if no status type */
int tlsext_status_type;
/* Expect OCSP CertificateStatus message */
int tlsext_status_expected;
/* OCSP status request only */
STACK_OF(OCSP_RESPID) *tlsext_ocsp_ids;
X509_EXTENSIONS *tlsext_ocsp_exts;
/* OCSP response received or to be sent */
unsigned char *tlsext_ocsp_resp;
int tlsext_ocsp_resplen;
/* RFC4507 session ticket expected to be received or sent */
int tlsext_ticket_expected;
#ifndef OPENSSL_NO_EC
size_t tlsext_ecpointformatlist_length;
unsigned char *tlsext_ecpointformatlist; /* our list */
size_t tlsext_ellipticcurvelist_length;
unsigned char *tlsext_ellipticcurvelist; /* our list */
#endif /* OPENSSL_NO_EC */
/* draft-rescorla-tls-opaque-prf-input-00.txt information to be used for handshakes */
void *tlsext_opaque_prf_input;
size_t tlsext_opaque_prf_input_len;
/* TLS Session Ticket extension override */
TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
/* TLS Session Ticket extension callback */
tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
void *tls_session_ticket_ext_cb_arg;
/* TLS pre-shared secret session resumption */
tls_session_secret_cb_fn tls_session_secret_cb;
void *tls_session_secret_cb_arg;
SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
#define session_ctx initial_ctx
#else
#define session_ctx ctx
#endif /* OPENSSL_NO_TLSEXT */
};
列出SSL方法结构SSL_METHOD如下:
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
int version;
int (*ssl_new)(SSL *s);
void (*ssl_clear)(SSL *s);
void (*ssl_free)(SSL *s);
int (*ssl_accept)(SSL *s);
int (*ssl_connect)(SSL *s);
int (*ssl_read)(SSL *s,void *buf,int len);
int (*ssl_peek)(SSL *s,void *buf,int len);
int (*ssl_write)(SSL *s,const void *buf,int len);
int (*ssl_shutdown)(SSL *s);
int (*ssl_renegotiate)(SSL *s);
int (*ssl_renegotiate_check)(SSL *s);
long (*ssl_get_message)(SSL *s, int st1, int stn, int mt, long
max, int *ok);
int (*ssl_read_bytes)(SSL *s, int type, unsigned char *buf, int len,
int peek);
int (*ssl_write_bytes)(SSL *s, int type, const void *buf_, int len);
int (*ssl_dispatch_alert)(SSL *s);
long (*ssl_ctrl)(SSL *s,int cmd,long larg,void *parg);
long (*ssl_ctx_ctrl)(SSL_CTX *ctx,int cmd,long larg,void *parg);
const SSL_CIPHER *(*get_cipher_by_char)(const unsigned char *ptr);
int (*put_cipher_by_char)(const SSL_CIPHER *cipher,unsigned char *ptr);
int (*ssl_pending)(const SSL *s);
int (*num_ciphers)(void);
const SSL_CIPHER *(*get_cipher)(unsigned ncipher);
const struct ssl_method_st *(*get_ssl_method)(int version);
long (*get_timeout)(void);
struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */
int (*ssl_version)(void);
long (*ssl_callback_ctrl)(SSL *s, int cb_id, void (*fp)(void));
long (*ssl_ctx_callback_ctrl)(SSL_CTX *s, int cb_id, void (*fp)(void));
} SSL_METHOD;