esock_openssl.c

来自「OTP是开放电信平台的简称」· C语言 代码 · 共 1,212 行 · 第 1/3 页

C
1,212
字号
 * */int esock_ssl_connect(Connection *cp){    int ret, ssl_error;    SSL *ssl = cp->opaque;    RESET_ERRSTR();    DEBUGF(("esock_ssl_connect: calling SSL_connect fd = %d\n"	    "  state before: %s\n", cp->fd, SSL_state_string(ssl)));    ret = SSL_connect(ssl);    ssl_error = SSL_get_error(ssl, ret);    DEBUGF(("  SSL_connect() = %d\n"	    "  ssl_error: %s\n"	    "  state after: %s\n", 	    ret, ssl_error_str(ssl_error), SSL_state_string(ssl)));    if (ret > 0)	return ret;    else if (ret == 0) {	/* permanent connect error */	sock_set_errno(ERRNO_NONE);	MAYBE_SET_ERRSTR("esslconnect");	return -1;    }    end_ssl_call(ret, cp, ssl_error);    return ret;}int esock_ssl_session_reused(Connection *cp){    SSL *ssl = cp->opaque;    return SSL_session_reused(ssl);}/* esock_ssl_read(Connection *cp, char *buf, int len) * * Read at most `len' chars into `buf'. Returns number of chars * read ( > 0), or 0 at EOF, or -1 on error. Sets cp->eof, cp->bp if * appropriate.  */int esock_ssl_read(Connection *cp, char *buf, int len){    int ret, ssl_error;    SSL *ssl = cp->opaque;    RESET_ERRSTR();    DEBUGF(("esock_ssl_read: calling SSL_read fd = %d\n"	    "  state before: %s\n", cp->fd, SSL_state_string(ssl)));    ret = SSL_read(ssl, buf, len);    ssl_error = SSL_get_error(ssl, ret);    DEBUGF(("  SSL_read = %d\n"	    "  ssl_error: %s\n"	    "  state after: %s\n", 	    ret, ssl_error_str(ssl_error), SSL_state_string(ssl)));    if (ssl_error == SSL_ERROR_NONE) {	DEBUGMSGF(("message (hex) : [%3.*a]\n", ret, buf));	DEBUGMSGF(("message (char): [%3.*b]\n", ret, buf));    }    if (ret > 0)	return ret;    if (ret == 0) {	check_shutdown(cp);	return ret;    }     end_ssl_call(ret, cp, ssl_error);    return ret;}/*  * esock_ssl_write(Connection *cp, char *buf, int len) * * Writes at most `len' chars from `buf'. Returns number of chars * written, or -1 on error. */int esock_ssl_write(Connection *cp, char *buf, int len){    int ret, ssl_error;    SSL *ssl = cp->opaque;    RESET_ERRSTR();    DEBUGF(("esock_ssl_write: calling SSL_write fd = %d\n"	    "  state before: %s\n", cp->fd, SSL_state_string(ssl)));    ret = SSL_write(ssl, buf, len);    ssl_error = SSL_get_error(ssl, ret);    DEBUGF(("  SSL_write = %d\n"	    "  ssl_error: %s\n"	    "  state after: %s\n", 	    ret, ssl_error_str(ssl_error), SSL_state_string(ssl)));    if (ssl_error == SSL_ERROR_NONE) {	DEBUGMSGF(("message (hex) : [%3.*a]\n", ret, buf));	DEBUGMSGF(("message (char): [%3.*b]\n", ret, buf));    }    if (ret > 0)	return ret;    if (ret == 0) {	check_shutdown(cp);	return ret;    }     end_ssl_call(ret, cp, ssl_error);    return ret;}int esock_ssl_shutdown(Connection *cp){    int ret, ssl_error;    SSL *ssl = cp->opaque;    RESET_ERRSTR();    DEBUGF(("esock_ssl_shutdown: calling SSL_shutdown fd = %d\n"    "  state before: %s\n",  cp->fd, SSL_state_string(ssl)));    ret = SSL_shutdown(ssl);    ssl_error = SSL_get_error(ssl, ret);    DEBUGF(("  SSL_shutdown = %d\n"	    "  ssl_error: %s\n"	    "  state after: %s\n",	    ret, ssl_error_str(ssl_error), SSL_state_string(ssl)));    if (ret >= 0) {	check_shutdown(cp);	return ret;    }    end_ssl_call(ret, cp, ssl_error);    return ret;}/* Returns total number of bytes in DER encoded cert pointed to by * *buf, which is allocated by this function, unless return < 0.   * XXX X509_free ?? */int esock_ssl_getpeercert(Connection *cp, unsigned char **buf){    int len;    SSL *ssl = cp->opaque;    X509 *x509;    unsigned char *tmp;    RESET_ERRSTR();    if((x509 = SSL_get_peer_certificate(ssl)) == NULL) {	MAYBE_SET_ERRSTR("enopeercert"); /* XXX doc */	return -1;    }        if ((len = i2d_X509(x509, NULL)) <= 0) {	MAYBE_SET_ERRSTR("epeercert");	return -1;    }    tmp = *buf = esock_malloc(len);    /* We must use a temporary value here, since i2d_X509(X509 *x,     * unsigned char **out) increments *out.       */    if (i2d_X509(x509, &tmp) < 0) {	esock_free(tmp);	MAYBE_SET_ERRSTR("epeercert");	return -1;    }    return len;}/* Returns total number of bytes in chain of certs. Each cert begins * with a 4-bytes length. The last cert is ended with 4-bytes of * zeros. The result is returned in *buf, which is allocated unless * the return value is < 0.   * XXX X509_free ? sk_X509_free ?  * XXX X509_free is reference counting. */int esock_ssl_getpeercertchain(Connection *cp, unsigned char **buf){    SSL *ssl = cp->opaque;    STACK_OF(X509) *x509_stack;    X509 *x509;    int num, i, totlen, pos, *der_len;    unsigned char *vbuf;    RESET_ERRSTR();    if((x509_stack = SSL_get_peer_cert_chain(ssl)) == NULL) {	MAYBE_SET_ERRSTR("enopeercertchain"); /* XXX doc */	return -1;    }        num = sk_X509_num(x509_stack);    der_len = esock_malloc(num * sizeof(int));    totlen = 0;    for (i = 0; i < num; i++) {	x509 = sk_X509_value(x509_stack, i);	totlen += 4;	if ((der_len[i] = i2d_X509(x509, NULL)) < 0) {	    MAYBE_SET_ERRSTR("epeercertchain");	    esock_free(der_len);	    return -1;	}	totlen += der_len[i];    }    totlen += 4;    vbuf = *buf = esock_malloc(totlen);    pos = 0;    for (i = 0; i < num; i++) {	x509 = sk_X509_value(x509_stack, i);	PUT_INT32(der_len[i], vbuf);	vbuf += 4;	/* Note: i2d_X509 increments vbuf */	if (i2d_X509(x509, &vbuf) < 0) {	    MAYBE_SET_ERRSTR("epeercertchain");	    esock_free(*buf);	    esock_free(der_len);	    return -1;	}    }    esock_free(der_len);    return totlen;}int esock_ssl_getprotocol_version(Connection *cp, char **buf){    SSL *ssl = cp->opaque;    RESET_ERRSTR();    if (!ssl) {	MAYBE_SET_ERRSTR("enoent");	return -1;    }    *buf = (char *) SSL_get_version(ssl);    return 0;}int esock_ssl_getcipher(Connection *cp, char **buf){    SSL *ssl = cp->opaque;    RESET_ERRSTR();    if (!ssl) {	MAYBE_SET_ERRSTR("enoent");	return -1;    }    *buf = (char *) SSL_get_cipher(ssl);    return 0;}/* Local functions */static char *ssl_error_str(int ssl_error){    int i;    static char buf[128];    for (i = 0; i < sizeof(errs)/sizeof(err_entry); i ++) {	if (ssl_error == errs[i].code)	    return errs[i].text;    }    sprintf(buf, "esock_openssl: SSL_error unknown: %d", ssl_error);    return buf;}void end_ssl_call(int ret, Connection *cp, int ssl_error){    SET_WANT(cp, ssl_error);    switch (ssl_error) {    case SSL_ERROR_SYSCALL:	/* Typically sock_errno() is equal to ERRNO_BLOCK */	MAYBE_SET_ERRSTR(esock_posix_str(sock_errno()));	break;    case SSL_ERROR_SSL:	sock_set_errno(ERRNO_NONE);	MAYBE_SET_ERRSTR("esslerrssl");	break;    case SSL_ERROR_WANT_X509_LOOKUP:	SSLDEBUGF();	sock_set_errno(ERRNO_NONE);	MAYBE_SET_ERRSTR("ex509lookup");	break;    case SSL_ERROR_WANT_CONNECT:	SSLDEBUGF();	sock_set_errno(ERRNO_NONE);	MAYBE_SET_ERRSTR("ewantconnect");	break;    default:	break;    }}void check_shutdown(Connection *cp) {    int sd_mode;    SSL *ssl = cp->opaque;    sd_mode = SSL_get_shutdown(ssl);    if (sd_mode & SSL_RECEIVED_SHUTDOWN)	cp->eof = 1;    if (sd_mode & SSL_SENT_SHUTDOWN) {	DEBUGF(("check_shutdown SSL_SENT_SHUTDOWN\n"));	cp->bp = 1;    }}/*  * set_ssl_parameters * * Set ssl parameters from connection structure. Only called for * listen and connect.  * * Note: The -cacertdir option is not documented. */static int set_ssl_parameters(Connection *cp, SSL_CTX *ctx){    char *cacertfile = NULL, *cacertdir = NULL, *certfile = NULL;    char *keyfile = NULL, *ciphers = NULL, *password = NULL;    int verify = 0, verify_depth = DEFAULT_VERIFY_DEPTH, verify_mode;    int i, argc;    char **argv;    callback_data *cb_data;    RESET_ERRSTR();    argc = esock_build_argv(cp->flags, &argv);    DEBUGF(("Argv:\n"));    for (i = 0; i < argc; i++) {	DEBUGF(("%d:  %s\n", i, argv[i]));    }    for (i = 0; i < argc; i++) {	if (strcmp(argv[i], "-verify") == 0) {	    verify = atoi(argv[++i]);	} else if (strcmp(argv[i], "-depth") == 0) {	    verify_depth = atoi(argv[++i]);	} else if (strcmp(argv[i], "-log") == 0) {	    /* XXX  ignored: logging per connection not supported */	    i++;	} else if (strcmp(argv[i], "-certfile") == 0) {	    certfile = argv[++i];	} else if (strcmp(argv[i], "-keyfile") == 0) {	    keyfile = argv[++i];	} else if (strcmp(argv[i], "-password") == 0) {	    password = argv[++i];	} else if (strcmp(argv[i], "-cacertfile") == 0) {	    cacertfile = argv[++i];	} else if (strcmp(argv[i], "-cacertdir") == 0) {	    cacertdir = argv[++i];	} else if (strcmp(argv[i], "-d") == 0) {	    /* XXX  ignored: debug per connection not supported */	    i++;	} else if (strcmp(argv[i], "-ciphers") == 0) {	    ciphers = argv[++i];	} else {	    /* XXX Error: now ignored */	}    }    DEBUGF(("set_ssl_parameters: all arguments read\n"));    if (cp->origin == ORIG_LISTEN && !certfile) {	DEBUGF(("ERROR: Server must have certificate\n"));	MAYBE_SET_ERRSTR("enoservercert");	goto err_end;    }    /* Define callback data */    /* XXX Check for NULL */    cb_data = esock_malloc(sizeof(callback_data));    cb_data->ctx = ctx;    if (password) {	cb_data->passwd = esock_malloc(strlen(password) + 1);	strcpy(cb_data->passwd, password);    } else	cb_data->passwd = NULL;    cb_data->verify_depth = verify_depth;    SSL_CTX_set_ex_data(ctx, callback_data_index, cb_data);    /* password callback */    SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);    SSL_CTX_set_default_passwd_cb_userdata(ctx, cb_data);    /* Set location for "trusted" certificates */    if (cacertfile || cacertdir) {	int res;	DEBUGF(("set_ssl_parameters: SSL_CTX_load_verify_locations\n"));	FOPEN_WORKAROUND(res, SSL_CTX_load_verify_locations(ctx, cacertfile,							    cacertdir));	if (!res) {	    DEBUGF(("ERROR: Cannot load verify locations\n"));	    MAYBE_SET_ERRSTR("ecacertfile");	    goto err_end;	}    } else {	int res;	DEBUGF(("set_ssl_parameters: SSL_CTX_set_default_verify_paths\n"));	FOPEN_WORKAROUND(res, SSL_CTX_set_default_verify_paths(ctx));	if (!res) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?