📄 myssl_nss.c
字号:
/***************************************************************************//* This code is part of WWW grabber called pavuk *//* Copyright (c) 1997 - 2001 Stefan Ondrejicka *//* Distributed under GPL 2 or later *//***************************************************************************/#include "config.h"#if defined(USE_SSL) && defined(USE_SSL_IMPL_NSS)#include <string.h>#include <time.h>#include <sys/ioctl.h>#include <secutil.h>#include <sslproto.h>#include "myssl.h"#include "http.h"#include "bufio.h"#include "errcode.h"#include "tools.h"#define PR_DESC_PAVUK_BUFIO 8static PRInt32 PR_CALLBACK myssl_bufio_avail(PRFileDesc * fd){ PRInt32 result; bufio *sock; sock = (bufio *) fd->secret; if(ioctl(sock->fd, FIONREAD, &result) < 0) result = -1; else result += sock->buf_end - sock->buf_start; return result;}static PRInt64 PR_CALLBACK myssl_bufio_avail64(PRFileDesc * fd){ return myssl_bufio_avail(fd);}static PRStatus PR_CALLBACK myssl_bufio_close(PRFileDesc * fd){ return PR_SUCCESS;}static PRStatus PR_CALLBACK myssl_bufio_sync(PRFileDesc * fd){ return PR_SUCCESS;}static PRStatus PR_CALLBACK myssl_bufio_connect(PRFileDesc * fd, const PRNetAddr * addr, PRIntervalTime timeout){ return PR_SUCCESS;}static PRInt32 PR_CALLBACK myssl_bufio_read(PRFileDesc * fd, void *buf, PRInt32 len){ PRInt32 rv; bufio *sock; sock = (bufio *) fd->secret; rv = bufio_nbfread(sock, buf, len); return rv;}static PRInt32 PR_CALLBACK myssl_bufio_recv(PRFileDesc * fd, void *buf, PRInt32 len, PRIntn flags, PRIntervalTime timeout){ return myssl_bufio_read(fd, buf, len);}static PRInt32 PR_CALLBACK myssl_bufio_write(PRFileDesc * fd, void *buf, PRInt32 len){ PRInt32 rv; bufio *sock; sock = (bufio *) fd->secret; rv = bufio_write(sock, buf, len); return rv;}static PRInt32 PR_CALLBACK myssl_bufio_send(PRFileDesc * fd, void *buf, PRInt32 len, PRIntn flags, PRIntervalTime timeout){ return myssl_bufio_write(fd, buf, len);}static PRInt16 PR_CALLBACK myssl_bufio_poll(PRFileDesc * fd, PRInt16 in_flags, PRInt16 * out_flags){ *out_flags = 0; if((in_flags & PR_POLL_READ) && myssl_bufio_avail(fd) > 0) *out_flags = PR_POLL_READ; return in_flags;}static PRStatus PR_CALLBACK myssl_bufio_getpeername(PRFileDesc * fd, PRNetAddr * addr){ bufio *sock; PRUint32 len; len = sizeof(PRNetAddr); sock = (bufio *) fd->secret; if(!getpeername(bufio_getfd(sock), (struct sockaddr *) addr, &len)) return PR_SUCCESS; else return PR_FAILURE;}static PRStatus PR_CALLBACK myssl_bufio_getsockopt(PRFileDesc * fd, PRSocketOptionData * data){ if(data->option == PR_SockOpt_Nonblocking) { data->value.non_blocking = FALSE; return PR_SUCCESS; } return PR_FAILURE;}/* FIXME: externs should be in an include file */extern PRIntn _PR_InvalidInt(void);extern PRInt64 _PR_InvalidInt64(void);extern PRStatus _PR_InvalidStatus(void);extern PRFileDesc *_PR_InvalidDesc(void);static const PRIOMethods myssl_bufio_methods = { PR_DESC_PAVUK_BUFIO, myssl_bufio_close, myssl_bufio_read, myssl_bufio_write, myssl_bufio_avail, myssl_bufio_avail64, myssl_bufio_sync, (PRSeekFN) _PR_InvalidInt, (PRSeek64FN) _PR_InvalidInt64, (PRFileInfoFN) _PR_InvalidStatus, (PRFileInfo64FN) _PR_InvalidStatus, (PRWritevFN) _PR_InvalidInt, myssl_bufio_connect, (PRAcceptFN) _PR_InvalidDesc, (PRBindFN) _PR_InvalidStatus, (PRListenFN) _PR_InvalidStatus, (PRShutdownFN) _PR_InvalidStatus, myssl_bufio_recv, myssl_bufio_send, (PRRecvfromFN) _PR_InvalidInt, (PRSendtoFN) _PR_InvalidInt, (PRPollFN) myssl_bufio_poll, (PRAcceptreadFN) _PR_InvalidInt, (PRTransmitfileFN) _PR_InvalidInt, (PRGetsocknameFN) _PR_InvalidStatus, myssl_bufio_getpeername, (PRReservedFN) _PR_InvalidInt, (PRReservedFN) _PR_InvalidInt, myssl_bufio_getsockopt, (PRSetsocketoptionFN) _PR_InvalidStatus, (PRSendfileFN) _PR_InvalidInt, (PRReservedFN) _PR_InvalidInt, (PRReservedFN) _PR_InvalidInt, (PRReservedFN) _PR_InvalidInt, (PRReservedFN) _PR_InvalidInt, (PRReservedFN) _PR_InvalidInt,};static void myssl_bufio_init_io_layer(void){ static int inited = FALSE; if(!inited) { myssl_bufio_methods.file_type = PR_GetUniqueIdentity("Pavuk_bufio"); inited = FALSE; } inited = TRUE;}static PRFileDesc *myssl_bufio_get_io_layer(void){ myssl_bufio_init_io_layer(); return PR_CreateIOLayerStub(myssl_bufio_methods.file_type, &myssl_bufio_methods);}static PRFileDesc *myssl_bufio_new_socket(bufio * sock){ PRFileDesc *fd; fd = myssl_bufio_get_io_layer(); fd->secret = (PRFilePrivate *) sock; return fd;}static char *my_ssl_passwd_callback(PK11SlotInfo * slot, PRBool retry, void *arg){ char *passwd = NULL; if(!retry && arg) passwd = PL_strdup((char *) arg); return passwd;}static SECStatus my_ssl_verify_callback(void *arg, PRFileDesc * fd, PRBool check_sig, PRBool is_server){ SECStatus rv; CERTCertificate *cert; cert = SSL_PeerCertificate(fd); DEBUG_SSL("Subject: %s\n", cert->subjectName); DEBUG_SSL("Issuer: %s\n", cert->issuerName); rv = SSL_AuthCertificate(arg, fd, check_sig, is_server); if(rv == SECSuccess) DEBUG_SSL("SSL certificate valid.\n"); CERT_DestroyCertificate(cert); return rv;}static SECStatus my_ssl_verify_failed_callback(void *arg, PRFileDesc * fd){ int err = PR_GetError(); DEBUG_SSL("SSL certificate invalid (%d).\n", err); DEBUG_SSL("%s\n", SECU_Strerror(err)); return cfg.nss_accept_unknown_cert ? SECSuccess : SECFailure;}void my_ssl_init(void){}void my_ssl_init_once(void){ PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);}void my_ssl_init_start(void){ SECStatus rv; char *certDir = priv_cfg.nss_cert_dir; static bool_t called = FALSE; if(called) NSS_Shutdown(); else called = TRUE; if(!certDir) { /* Look in $SSL_DIR */ certDir = SECU_DefaultSSLDir(); /* call even if it's NULL */ certDir = SECU_ConfigDirectory(certDir); } DEBUG_SSL("myssl_nss: config dir %s\n", certDir ? certDir : "(null)"); if(priv_cfg.ssl_cert_passwd) PK11_SetPasswordFunc(my_ssl_passwd_callback); else PK11_SetPasswordFunc(SECU_GetModulePassword); rv = NSS_Init(certDir); if(rv != SECSuccess) xprintf(1, gettext("NSS_Init: Unable to open cert database")); if(cfg.nss_domestic_policy) NSS_SetDomesticPolicy(); else NSS_SetExportPolicy();}void my_ssl_cleanup(void){ NSS_Shutdown(); PR_Cleanup();}void my_ssl_connection_close(ssl_connection * con){ if(con->fd) PR_Close(con->fd); if(con->socket) bufio_close(con->socket); con->fd = NULL; con->socket = NULL;}void my_ssl_connection_destroy(ssl_connection * con){ my_ssl_connection_close(con); _free(con);}static ssl_connection *my_ssl_connection_new(void){ ssl_connection *con; con = _malloc(sizeof(ssl_connection)); con->fd = NULL; con->socket = NULL; return con;}static const struct{ int cipher; char *name;} my_ssl_cipher_tab[] ={ {SSL_EN_RC4_128_WITH_MD5, "EN_RC4_128_WITH_MD5"}, {SSL_EN_RC4_128_EXPORT40_WITH_MD5, "EN_RC4_128_EXPORT40_WITH_MD5"}, {SSL_EN_RC2_128_CBC_WITH_MD5, "EN_RC2_128_CBC_WITH_MD5"}, {SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, "EN_RC2_128_CBC_EXPORT40_WITH_MD5"}, {SSL_EN_DES_64_CBC_WITH_MD5, "EN_DES_64_CBC_WITH_MD5"}, {SSL_EN_DES_192_EDE3_CBC_WITH_MD5, "EN_DES_192_EDE3_CBC_WITH_MD5"}, {SSL_NULL_WITH_NULL_NULL, "NULL_WITH_NULL_NULL"}, {SSL_RSA_WITH_NULL_MD5, "RSA_WITH_NULL_MD5"}, {SSL_RSA_WITH_NULL_SHA, "RSA_WITH_NULL_SHA"}, {SSL_RSA_EXPORT_WITH_RC4_40_MD5, "RSA_EXPORT_WITH_RC4_40_MD5"}, {SSL_RSA_WITH_RC4_128_MD5, "RSA_WITH_RC4_128_MD5"}, {SSL_RSA_WITH_RC4_128_SHA, "RSA_WITH_RC4_128_SHA"}, {SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, "RSA_EXPORT_WITH_RC2_CBC_40_MD5"}, {SSL_RSA_WITH_IDEA_CBC_SHA, "RSA_WITH_IDEA_CBC_SHA"}, {SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, "RSA_EXPORT_WITH_DES40_CBC_SHA"}, {SSL_RSA_WITH_DES_CBC_SHA, "RSA_WITH_DES_CBC_SHA"}, {SSL_RSA_WITH_3DES_EDE_CBC_SHA, "RSA_WITH_3DES_EDE_CBC_SHA"}, {SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, "DH_DSS_EXPORT_WITH_DES40_CBC_SHA"}, {SSL_DH_DSS_WITH_DES_CBC_SHA, "DH_DSS_WITH_DES_CBC_SHA"}, {SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA, "DH_DSS_WITH_3DES_EDE_CBC_SHA"}, {SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, "DH_RSA_EXPORT_WITH_DES40_CBC_SHA"}, {SSL_DH_RSA_WITH_DES_CBC_SHA, "DH_RSA_WITH_DES_CBC_SHA"}, {SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA, "DH_RSA_WITH_3DES_EDE_CBC_SHA"}, {SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, "DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"}, {SSL_DHE_DSS_WITH_DES_CBC_SHA, "DHE_DSS_WITH_DES_CBC_SHA"}, {SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, "DHE_DSS_WITH_3DES_EDE_CBC_SHA"}, {SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, "DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"}, {SSL_DHE_RSA_WITH_DES_CBC_SHA, "DHE_RSA_WITH_DES_CBC_SHA"}, {SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, "DHE_RSA_WITH_3DES_EDE_CBC_SHA"}, {SSL_DH_ANON_EXPORT_WITH_RC4_40_MD5, "DH_ANON_EXPORT_WITH_RC4_40_MD5"}, {SSL_DH_ANON_WITH_RC4_128_MD5, "DH_ANON_WITH_RC4_128_MD5"}, {SSL_DH_ANON_EXPORT_WITH_DES40_CBC_SHA, "DH_ANON_EXPORT_WITH_DES40_CBC_SHA"}, {SSL_DH_ANON_WITH_DES_CBC_SHA, "DH_ANON_WITH_DES_CBC_SHA"}, {SSL_DH_ANON_WITH_3DES_EDE_CBC_SHA, "DH_ANON_WITH_3DES_EDE_CBC_SHA"}, {SSL_FORTEZZA_DMS_WITH_NULL_SHA, "FORTEZZA_DMS_WITH_NULL_SHA"}, {SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, "FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA"}, {SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, "FORTEZZA_DMS_WITH_RC4_128_SHA"}, {TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, "RSA_EXPORT1024_WITH_DES_CBC_SHA"}, {TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, "RSA_EXPORT1024_WITH_RC4_56_SHA"}, {TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA, "DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA"}, {TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA, "DHE_DSS_EXPORT1024_WITH_RC4_56_SHA"}, {TLS_DHE_DSS_WITH_RC4_128_SHA, "DHE_DSS_WITH_RC4_128_SHA"}, {SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA, "RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA"}, {SSL_RSA_OLDFIPS_WITH_DES_CBC_SHA, "RSA_OLDFIPS_WITH_DES_CBC_SHA"}, {SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, "RSA_FIPS_WITH_3DES_EDE_CBC_SHA"}, {SSL_RSA_FIPS_WITH_DES_CBC_SHA, "RSA_FIPS_WITH_DES_CBC_SHA"}};static int my_ssl_get_cipher_by_name(char *n){ int i; for(i = 0; i < NUM_ELEM(my_ssl_cipher_tab); i++) { if(!strcasecmp(n, my_ssl_cipher_tab[i].name)) return my_ssl_cipher_tab[i].cipher; } DEBUG_SSL("unknown NSS3 SSL cipher %s\n", n); return -1;}static void my_ssl_set_ciphers(PRFileDesc * fd, char *ciphers){ char **c; int cipher, i; if(!strcasecmp(ciphers, "all")) return; c = tl_str_split(ciphers, ","); /* at first disable all ciphers */ for(i = 0; i < NUM_ELEM(my_ssl_cipher_tab); i++) { cipher = my_ssl_cipher_tab[i].cipher; if(fd) SSL_CipherPrefSet(fd, cipher, SSL_NOT_ALLOWED); } for(i = 0; c && c[i]; i++) { cipher = my_ssl_get_cipher_by_name(c[i]); if(cipher != -1 && fd) SSL_CipherPrefSet(fd, cipher, SSL_ALLOWED); } tl_strv_free(c);}bufio *my_ssl_do_connect(doc * docp, bufio * socket, ssl_connection * parent_ssl_con){ int rv; ssl_connection *con; PRFileDesc *model; CERTCertDBHandle *handle; my_ssl_init(); if(priv_cfg.ssl_proxy) { if(http_dumy_proxy_connect(docp, url_get_site(docp->doc_url), url_get_port(docp->doc_url), priv_cfg.ssl_proxy, cfg.ssl_proxy_port)) { docp->errcode = ERR_PROXY_CONNECT; return NULL; } } con = my_ssl_connection_new(); model = myssl_bufio_new_socket(socket); /* model = PR_ImportTCPSocket(bufio_getfd(socket)); */ con->fd = SSL_ImportFD(NULL, model); SSL_OptionSet(con->fd, SSL_SECURITY, PR_TRUE); SSL_OptionSet(con->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); switch (cfg.ssl_version) { case 1: SSL_OptionSet(con->fd, SSL_ENABLE_SSL2, TRUE); SSL_OptionSet(con->fd, SSL_ENABLE_SSL3, FALSE); SSL_OptionSet(con->fd, SSL_ENABLE_TLS, FALSE); SSL_OptionSet(con->fd, SSL_V2_COMPATIBLE_HELLO, TRUE); break; case 2: SSL_OptionSet(con->fd, SSL_ENABLE_SSL2, TRUE); SSL_OptionSet(con->fd, SSL_ENABLE_SSL3, TRUE); SSL_OptionSet(con->fd, SSL_ENABLE_TLS, FALSE); SSL_OptionSet(con->fd, SSL_V2_COMPATIBLE_HELLO, TRUE); break; case 3: SSL_OptionSet(con->fd, SSL_ENABLE_SSL2, FALSE); SSL_OptionSet(con->fd, SSL_ENABLE_SSL3, TRUE); SSL_OptionSet(con->fd, SSL_ENABLE_TLS, FALSE); SSL_OptionSet(con->fd, SSL_V2_COMPATIBLE_HELLO, FALSE); break; case 4: SSL_OptionSet(con->fd, SSL_ENABLE_SSL2, FALSE); SSL_OptionSet(con->fd, SSL_ENABLE_SSL3, FALSE); SSL_OptionSet(con->fd, SSL_ENABLE_TLS, TRUE); SSL_OptionSet(con->fd, SSL_V2_COMPATIBLE_HELLO, FALSE); break; } SSL_OptionSet(con->fd, SSL_NO_CACHE, !cfg.unique_sslid); if(priv_cfg.ssl_cipher_list) my_ssl_set_ciphers(con->fd, priv_cfg.ssl_cipher_list); if(priv_cfg.ssl_cert_passwd) SSL_SetPKCS11PinArg(con->fd, priv_cfg.ssl_cert_passwd); handle = CERT_GetDefaultCertDB(); SSL_AuthCertificateHook(con->fd, my_ssl_verify_callback, (void *) handle); SSL_GetClientAuthDataHook(con->fd, NSS_GetClientAuthData, (void *) NULL); SSL_BadCertHook(con->fd, my_ssl_verify_failed_callback, (void *) NULL); SSL_SetURL(con->fd, url_get_site(docp->doc_url)); SSL_SetSockPeerID(con->fd, url_get_site(docp->doc_url)); rv = SSL_ResetHandshake(con->fd, 0); rv = SSL_ForceHandshake(con->fd); if(rv != SECSuccess) { const char *errstr; errstr = SECU_Strerror(PR_GetError()); xprintf(1, gettext("SSL connect failure - %s\n"), errstr); my_ssl_connection_destroy(con); return NULL; } con->socket = socket; return bufio_new_sslcon(socket, con);}int my_ssl_read(ssl_connection * ssl_con, char *buf, size_t len){ return PR_Read(ssl_con->fd, buf, len);}int my_ssl_write(ssl_connection * ssl_con, char *buf, size_t len){ return PR_Write(ssl_con->fd, buf, len);}int my_ssl_data_pending(ssl_connection * ssl_con){ return SSL_DataPending(ssl_con->fd);}void my_ssl_print_last_error(void){ char *errstr = SECU_Strerror(PR_GetError()); xprintf(1, gettext("SSL error - %s\n"), errstr);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -