diff options
Diffstat (limited to 'security/nss/cmd/sslstrength/sslstrength.c')
-rw-r--r-- | security/nss/cmd/sslstrength/sslstrength.c | 640 |
1 files changed, 640 insertions, 0 deletions
diff --git a/security/nss/cmd/sslstrength/sslstrength.c b/security/nss/cmd/sslstrength/sslstrength.c new file mode 100644 index 000000000..7351dfea0 --- /dev/null +++ b/security/nss/cmd/sslstrength/sslstrength.c @@ -0,0 +1,640 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef SSLTELNET +#include <termios.h> +#endif + +/* Portable layer header files */ +#include "prinit.h" +#include "prprf.h" +#include "prsystem.h" +#include "prmem.h" +#include "plstr.h" +#include "prnetdb.h" +#include "prinrval.h" + +#include "secutil.h" + +/* Security library files */ +#include "cert.h" +#include "ssl.h" +#include "sslproto.h" + +/* define this if you want telnet capability! */ + +/* #define SSLTELNET 1 */ + +PRInt32 debug; + +#ifdef DEBUG_stevep +#define dbmsg(x) if (verbose) PR_fprintf(PR_STDOUT,x); +#else +#define dbmsg(x) ; +#endif + + +/* Set SSL Policy to Domestic (strong=1) or Export (strong=0) */ + +#define ALLOW(x) SSL_CipherPolicySet(x,SSL_ALLOWED); SSL_CipherPrefSetDefault(x,1); +#define DISALLOW(x) SSL_CipherPolicySet(x,SSL_NOT_ALLOWED); SSL_CipherPrefSetDefault(x,0); +#define MAYBEALLOW(x) SSL_CipherPolicySet(x,SSL_RESTRICTED); SSL_CipherPrefSetDefault(x,1); + +struct CipherPolicy { + char number; + long id; + char *name; + PRInt32 pref; + PRInt32 domestic; + PRInt32 export; +}; + +struct CipherPolicy ciphers[] = { + { 'a',SSL_EN_RC4_128_WITH_MD5, "SSL_EN_RC4_128_WITH_MD5 (ssl2)",1, SSL_ALLOWED,SSL_NOT_ALLOWED }, + { 'b',SSL_EN_RC2_128_CBC_WITH_MD5, "SSL_EN_RC2_128_CBC_WITH_MD5 (ssl2)",1, SSL_ALLOWED,SSL_NOT_ALLOWED }, + { 'c',SSL_EN_DES_192_EDE3_CBC_WITH_MD5, "SSL_EN_DES_192_EDE3_CBC_WITH_MD5 (ssl2)",1, SSL_ALLOWED,SSL_NOT_ALLOWED }, + { 'd',SSL_EN_DES_64_CBC_WITH_MD5, "SSL_EN_DES_64_CBC_WITH_MD5 (ssl2)",1, SSL_ALLOWED,SSL_NOT_ALLOWED }, + { 'e',SSL_EN_RC4_128_EXPORT40_WITH_MD5, "SSL_EN_RC4_128_EXPORT40_WITH_MD5 (ssl2)",1, SSL_ALLOWED,SSL_ALLOWED }, + { 'f',SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, "SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5 (ssl2)",1, SSL_ALLOWED,SSL_ALLOWED }, +#ifdef FORTEZZA + { 'g',SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA",1,SSL_ALLOWED,SSL_NOT_ALLOWED }, + { 'h',SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, "SSL_FORTEZZA_DMS_WITH_RC4_128_SHA",1, SSL_ALLOWED,SSL_NOT_ALLOWED }, +#endif + { 'i',SSL_RSA_WITH_RC4_128_MD5, "SSL_RSA_WITH_RC4_128_MD5 (ssl3)",1, SSL_ALLOWED,SSL_RESTRICTED }, + { 'j',SSL_RSA_WITH_3DES_EDE_CBC_SHA, "SSL_RSA_WITH_3DES_EDE_CBC_SHA (ssl3)",1, SSL_ALLOWED,SSL_RESTRICTED }, + { 'k',SSL_RSA_WITH_DES_CBC_SHA, "SSL_RSA_WITH_DES_CBC_SHA (ssl3)",1, SSL_ALLOWED,SSL_NOT_ALLOWED }, + { 'l',SSL_RSA_EXPORT_WITH_RC4_40_MD5, "SSL_RSA_EXPORT_WITH_RC4_40_MD5 (ssl3)",1, SSL_ALLOWED,SSL_ALLOWED }, + { 'm',SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 (ssl3)",1, SSL_ALLOWED,SSL_ALLOWED }, +#ifdef FORTEZZA + { 'n',SSL_FORTEZZA_DMS_WITH_NULL_SHA, "SSL_FORTEZZA_DMS_WITH_NULL_SHA",1, SSL_ALLOWED,SSL_NOT_ALLOWED }, +#endif + { 'o',SSL_RSA_WITH_NULL_MD5, "SSL_RSA_WITH_NULL_MD5 (ssl3)",1, SSL_ALLOWED,SSL_ALLOWED }, + { 'p',SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA (ssl3)",1, SSL_ALLOWED,SSL_NOT_ALLOWED }, + { 'q',SSL_RSA_FIPS_WITH_DES_CBC_SHA, "SSL_RSA_FIPS_WITH_DES_CBC_SHA (ssl3)",1, SSL_ALLOWED,SSL_NOT_ALLOWED } + +}; + +void PrintErrString(char *progName,char *msg) { + + PRErrorCode e = PORT_GetError(); + char *s=NULL; + + + if ((e >= PR_NSPR_ERROR_BASE) && (e < PR_MAX_ERROR)) { + + if (e == PR_DIRECTORY_LOOKUP_ERROR) + s = PL_strdup("Hostname Lookup Failed"); + else if (e == PR_NETWORK_UNREACHABLE_ERROR) + s = PL_strdup("Network Unreachable"); + else if (e == PR_CONNECT_TIMEOUT_ERROR) + s = PL_strdup("Connection Timed Out"); + else s = PR_smprintf("%d",e); + + if (!s) return; + } + else { + s = PL_strdup(SECU_ErrorString(e)); + } + + PR_fprintf(PR_STDOUT,"%s: ",progName); + if (s) { + if (strlen(s) > 0) + PR_fprintf(PR_STDOUT, "%s\n", s); + else + PR_fprintf(PR_STDOUT, "\n"); + + PR_Free(s); + } + +} + +void PrintCiphers(int onlyenabled) { + int ciphercount,i; + + if (onlyenabled) { + PR_fprintf(PR_STDOUT,"Your Cipher preference:\n"); + } + + ciphercount = sizeof(ciphers)/sizeof(struct CipherPolicy); + PR_fprintf(PR_STDOUT, + " %s %-45s %-12s %-12s\n","id","CipherName","Domestic","Export"); + + for (i=0;i<ciphercount;i++) { + if ( (onlyenabled ==0) || ((onlyenabled==1)&&(ciphers[i].pref))) { + PR_fprintf(PR_STDOUT, + " %c %-45s %-12s %-12s\n",ciphers[i].number,ciphers[i].name, + (ciphers[i].domestic==SSL_ALLOWED)?"Yes": + ( (ciphers[i].domestic==SSL_NOT_ALLOWED)?"No":"Step-up only"), + (ciphers[i].export==SSL_ALLOWED)?"Yes": + ( (ciphers[i].export==SSL_NOT_ALLOWED)?"No":"Step-up only")); + } + } +} + + +void SetPolicy(char *c,int policy) { /* policy==1 : domestic, policy==0, export */ + int i,j,cpolicy; + /* first, enable all relevant ciphers according to policy */ + for (j=0;j<(sizeof(ciphers)/sizeof(struct CipherPolicy));j++) { + SSL_CipherPolicySet(ciphers[j].id,policy?ciphers[j].domestic:ciphers[j].export); + SSL_CipherPrefSetDefault(ciphers[j].id, PR_FALSE); + ciphers[j].pref =0; + } + + + for (i=0;i<PL_strlen(c);i++) { + for (j=0;j<(sizeof(ciphers)/sizeof(struct CipherPolicy));j++) { + if (ciphers[j].number == c[i]) { + cpolicy = policy?ciphers[j].domestic:ciphers[j].export; + if (cpolicy == SSL_NOT_ALLOWED) { + PR_fprintf(PR_STDOUT, "You're trying to enable a cipher (%c:%s) outside of your policy. ignored\n", + c[i],ciphers[j].name); + } + else { + ciphers[j].pref=1; + SSL_CipherPrefSetDefault(ciphers[j].id, PR_TRUE); + } + } + } + } +} + + +int MyAuthCertificateHook(void *arg, PRFileDesc *fd, PRBool checksig, PRBool isserver) { + return SECSuccess; +} + + +void Usage() { +#ifdef SSLTELNET + PR_fprintf(PR_STDOUT,"SSLTelnet "); +#else + PR_fprintf(PR_STDOUT,"SSLStrength (No telnet functionality) "); +#endif + PR_fprintf(PR_STDOUT,"Version 1.5\n"); + + PR_fprintf(PR_STDOUT,"Usage:\n sslstrength hostname[:port] [ciphers=xyz] [certdir=x] [debug] [verbose] " +#ifdef SSLTELNET +"[telnet]|[servertype]|[querystring=<string>] " +#endif +"[policy=export|domestic]\n sslstrength ciphers\n"); +} + + +PRInt32 debug = 0; +PRInt32 verbose = 0; + +PRInt32 main(PRInt32 argc,char **argv, char **envp) +{ + + + /* defaults for command line arguments */ + char *hostnamearg=NULL; + char *portnumarg=NULL; + char *sslversionarg=NULL; + char *keylenarg=NULL; + char *certdir=NULL; + char *hostname; + char *nickname=NULL; + char *progname=NULL; + /* struct sockaddr_in addr; */ + PRNetAddr addr; + + int ss_on; + char *ss_cipher; + int ss_keysize; + int ss_secretsize; + char *ss_issuer; + char *ss_subject; + int policy=1; + char *set_ssl_policy=NULL; + int print_ciphers=0; + + char buf[10]; + char netdbbuf[PR_NETDB_BUF_SIZE]; + PRHostEnt hp; + PRStatus r; + PRNetAddr na; + SECStatus rv; + int portnum=443; /* default https: port */ + PRFileDesc *s,*fd; + + CERTCertDBHandle *handle; + CERTCertificate *c; + PRInt32 i; +#ifdef SSLTELNET + struct termios tmp_tc; + char cb; + int prev_lflag,prev_oflag,prev_iflag; + int t_fin,t_fout; + int servertype=0, telnet=0; + char *querystring=NULL; +#endif + + debug = 0; + + progname = (char *)PL_strrchr(argv[0], '/'); + progname = progname ? progname+1 : argv[0]; + + /* Read in command line args */ + if (argc == 1) { + Usage(); + return(0); + } + + if (! PL_strcmp("ciphers",argv[1])) { + PrintCiphers(0); + exit(0); + } + + hostname = argv[1]; + + if (!PL_strcmp(hostname , "usage") || !PL_strcmp(hostname, "-help") ) { + Usage(); + exit(0); + } + + if ((portnumarg = PL_strchr(hostname,':'))) { + *portnumarg = 0; + portnumarg = &portnumarg[1]; + } + + if (portnumarg) { + if (PL_strlen(portnumarg) == 0) { + PR_fprintf(PR_STDOUT,"malformed port number supplied\n"); + return(1); + } + portnum = atoi(portnumarg); + } + + for (i = 2 ; i < argc; i++) + { + if (!PL_strncmp(argv[i] , "sslversion=",11) ) + sslversionarg=&(argv[i][11]); + else if (!PL_strncmp(argv[i], "certdir=",8) ) + certdir = &(argv[i][8]); + else if (!PL_strncmp(argv[i], "ciphers=",8) ) + { + set_ssl_policy=&(argv[i][8]); + } + else if (!PL_strncmp(argv[i], "policy=",7) ) { + if (!PL_strcmp(&(argv[i][7]),"domestic")) policy=1; + else if (!PL_strcmp(&(argv[i][7]),"export")) policy=0; + else { + PR_fprintf(PR_STDOUT,"sslstrength: invalid argument. policy must be one of (domestic,export)\n"); + } + } + else if (!PL_strcmp(argv[i] , "debug") ) + debug = 1; +#ifdef SSLTELNET + else if (!PL_strcmp(argv[i] , "telnet") ) + telnet = 1; + else if (!PL_strcmp(argv[i] , "servertype") ) + servertype = 1; + else if (!PL_strncmp(argv[i] , "querystring=",11) ) + querystring = &argv[i][12]; +#endif + else if (!PL_strcmp(argv[i] , "verbose") ) + verbose = 1; + } + +#ifdef SSLTELNET + if (telnet && (servertype || querystring)) { + PR_fprintf(PR_STDOUT,"You can't use telnet and (server or querystring) options at the same time\n"); + exit(1); + } +#endif + + PR_fprintf(PR_STDOUT,"Using %s policy\n",policy?"domestic":"export"); + + /* use current directory for certificate database if not set */ + + if (! certdir) { + certdir = PR_smprintf("."); + } + + SECU_ConfigDirectory(certdir); + + + /* allow you to set env var SSLDIR to set the cert directory */ + if (! certdir) certdir = SECU_DefaultSSLDir(); + if (certdir) SECU_ConfigDirectory(certdir); + + /* PR_Init(progname, 1, 1, 0); */ + SECU_PKCS11Init(PR_FALSE /*readOnly==PR_FALSE*/); + + /* Lookup host */ + r = PR_GetHostByName(hostname,netdbbuf,PR_NETDB_BUF_SIZE,&hp); + + if (r) { + PrintErrString(progname,"Host Name lookup failed"); + return(1); + } + + /* should the third field really be 0? */ + + PR_EnumerateHostEnt(0,&hp,0,&na); + PR_InitializeNetAddr(PR_IpAddrNull,portnum,&na); + + PR_fprintf(PR_STDOUT,"Connecting to %s:%d\n",hostname, portnum); + + /* Create socket */ + + fd = PR_NewTCPSocket(); + if (fd == NULL) { + PrintErrString(progname, "error creating socket"); + return -1; + } + + s = SSL_ImportFD(NULL,fd); + if (s == NULL) { + PrintErrString(progname, "error creating socket"); + return -1; + } + + /* Initialize all the libsec goodies */ + SEC_Init(); + + dbmsg("10: About to enable security\n"); + + rv = SSL_OptionSet(s, SSL_SECURITY, PR_TRUE); + if (rv < 0) { + PrintErrString(progname, "error enabling socket"); + return -1; + } + + if (set_ssl_policy) { + SetPolicy(set_ssl_policy,policy); + } + else { + PR_fprintf(PR_STDOUT,"Using all ciphersuites usually found in client\n"); + if (policy) { + SetPolicy("abcdefghijklmnopqrst",policy); + } + else { + SetPolicy("efghijlmo",policy); + } + } + + PrintCiphers(1); + + rv = SSL_OptionSet(s, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); + if (rv < 0) { + PrintErrString(progname, "error enabling client handshake"); + return -1; + } + + handle = (CERTCertDBHandle *)PORT_ZAlloc(sizeof(CERTCertDBHandle)); + if (!handle) { + PrintErrString(progname, "could not allocate database handle"); + return -1; + } + + dbmsg("20: About to open certificate database\n"); + + + /* Open up the certificate database */ + rv = CERT_OpenCertDBFilename(handle, "cert7.db", PR_TRUE); + if ( rv ) { + PrintErrString(progname, "unable to open cert database"); + rv = CERT_OpenVolatileCertDB(handle); + } + + CERT_SetDefaultCertDB(handle); + + dbmsg("30: About to set AuthCertificateHook\n"); + + + SSL_AuthCertificateHook(s, MyAuthCertificateHook, (void *)handle); + /* SSL_AuthCertificateHook(s, SSL_AuthCertificate, (void *)handle); */ + /* SSL_GetClientAuthDataHook(s, GetClientAuthDataHook, (void *)nickname);*/ + + + dbmsg("40: About to SSLConnect\n"); + + /* Try to connect to the server */ + /* now SSL_Connect takes new arguments. */ + + + r = PR_Connect(s, &na, PR_TicksPerSecond()*5); + if (r < 0) { + PrintErrString(progname, "unable to connect"); + return -1; + } + + rv = SSL_ForceHandshake(s); + + if (rv) { + PrintErrString(progname,"SSL Handshake failed. "); + exit(1); + } + + rv = SSL_SecurityStatus(s, &ss_on, &ss_cipher, + &ss_keysize, &ss_secretsize, + &ss_issuer, &ss_subject); + + + dbmsg("60: done with security status, about to print\n"); + + c = SSL_PeerCertificate(s); + if (!c) PR_fprintf(PR_STDOUT,"Couldn't retrieve peers Certificate\n"); + PR_fprintf(PR_STDOUT,"SSL Connection Status\n",rv); + + PR_fprintf(PR_STDOUT," Cipher: %s\n",ss_cipher); + PR_fprintf(PR_STDOUT," Key Size: %d\n",ss_keysize); + PR_fprintf(PR_STDOUT," Secret Key Size: %d\n",ss_secretsize); + PR_fprintf(PR_STDOUT," Issuer: %s\n",ss_issuer); + PR_fprintf(PR_STDOUT," Subject: %s\n",ss_subject); + + PR_fprintf(PR_STDOUT," Valid: from %s to %s\n", + c==NULL?"???":DER_UTCDayToAscii(&c->validity.notBefore), + c==NULL?"???":DER_UTCDayToAscii(&c->validity.notAfter)); + +#ifdef SSLTELNET + + + + + if (servertype || querystring) { + char buffer[1024]; + char ch; + char qs[] = "HEAD / HTTP/1.0"; + + + + + if (!querystring) querystring = qs; + PR_fprintf(PR_STDOUT,"\nServer query mode\n>>Sending:\n%s\n",querystring); + + PR_fprintf(PR_STDOUT,"\n*** Server said:\n"); + ch = querystring[PL_strlen(querystring)-1]; + if (ch == '"' || ch == '\'') { + PR_fprintf(PR_STDOUT,"Warning: I'm not smart enough to cope with quotes mid-string like that\n"); + } + + rv = PR_Write(s,querystring,PL_strlen(querystring)); + if ((rv < 1) ) { + PR_fprintf(PR_STDOUT,"Oh dear - couldn't send servertype query\n"); + goto closedown; + } + + rv = PR_Write(s,"\r\n\r\n",4); + rv = PR_Read(s,buffer,1024); + if ((rv < 1) ) { + PR_fprintf(PR_STDOUT,"Oh dear - couldn't read server repsonse\n"); + goto closedown; + } + PR_Write(PR_STDOUT,buffer,rv); + } + + + if (telnet) { + + PR_fprintf(PR_STDOUT,"---------------------------\n" + "telnet mode. CTRL-C to exit\n" + "---------------------------\n"); + + + + /* fudge terminal attributes */ + t_fin = PR_FileDesc2NativeHandle(PR_STDIN); + t_fout = PR_FileDesc2NativeHandle(PR_STDOUT); + + tcgetattr(t_fin,&tmp_tc); + prev_lflag = tmp_tc.c_lflag; + prev_oflag = tmp_tc.c_oflag; + prev_iflag = tmp_tc.c_iflag; + tmp_tc.c_lflag &= ~ECHO; + /* tmp_tc.c_oflag &= ~ONLCR; */ + tmp_tc.c_lflag &= ~ICANON; + tmp_tc.c_iflag &= ~ICRNL; + tmp_tc.c_cflag |= CS8; + tmp_tc.c_cc[VMIN] = 1; + tmp_tc.c_cc[VTIME] = 0; + + tcsetattr(t_fin, TCSANOW, &tmp_tc); + /* ioctl(tin, FIONBIO, (char *)&onoff); + ioctl(tout, FIONBIO, (char *)&onoff);*/ + + + { + PRPollDesc pds[2]; + char buffer[1024]; + int amt,amtwritten; + char *x; + + /* STDIN */ + pds[0].fd = PR_STDIN; + pds[0].in_flags = PR_POLL_READ; + pds[1].fd = s; + pds[1].in_flags = PR_POLL_READ | PR_POLL_EXCEPT; + + while (1) { + int nfds; + + nfds = PR_Poll(pds,2,PR_SecondsToInterval(2)); + if (nfds == 0) continue; + + /** read input from keyboard*/ + /* note: this is very inefficient if reading from a file */ + + if (pds[0].out_flags & PR_POLL_READ) { + amt = PR_Read(PR_STDIN,&buffer,1); + /* PR_fprintf(PR_STDOUT,"fd[0]:%d=%d\r\n",amt,buffer[0]); */ + if (amt == 0) { + PR_fprintf(PR_STDOUT,"\n"); + goto loser; + } + + if (buffer[0] == '\r') { + buffer[0] = '\r'; + buffer[1] = '\n'; + amt = 2; + } + rv = PR_Write(PR_STDOUT,buffer,amt); + + + rv = PR_Write(s,buffer,amt); + if (rv == -1) { + PR_fprintf(PR_STDOUT,"Error writing to socket: %d\n",PR_GetError()); + } + } + + /***/ + + + /***/ + if (pds[1].out_flags & PR_POLL_EXCEPT) { + PR_fprintf(PR_STDOUT,"\r\nServer closed connection\r\n"); + goto loser; + } + if (pds[1].out_flags & PR_POLL_READ) { + amt = PR_Read(s,&buffer,1024); + + if (amt == 0) { + PR_fprintf(PR_STDOUT,"\r\nServer closed connection\r\n"); + goto loser; + } + rv = PR_Write(PR_STDOUT,buffer,amt); + } + /***/ + + } + } + loser: + + /* set terminal back to normal */ + tcgetattr(t_fin,&tmp_tc); + + tmp_tc.c_lflag = prev_lflag; + tmp_tc.c_oflag = prev_oflag; + tmp_tc.c_iflag = prev_iflag; + tcsetattr(t_fin, TCSANOW, &tmp_tc); + + /* ioctl(tin, FIONBIO, (char *)&onoff); + ioctl(tout, FIONBIO, (char *)&onoff); */ + } + +#endif + /* SSLTELNET */ + + closedown: + + PR_Close(s); + + return(0); + +} /* main */ + +/*EOF*/ + |