Hi Wan-Teh Chang,
Please see some replies below.

Wan-Teh Chang wrote:
Yahel Zamir wrote:

1.
When writing an application that uses NSS, I would expect all Platform Dependent configuration to reside in some configuration file, so that the build process of the whole application will not need to be aware of these details. However, the platform name and other properties appear again and again in the Include path, the Library search path and in command line defines, as you can see below - the command is copied from running "make" in SSLsample, and contains many references to Linux, Unix, x86 etc. Am I missing something here?

... -DLINUX1_2 -Di386 -D_XOPEN_SOURCE -DLINUX2_1 -ansi -Wall -pipe -DHAVE_STRERROR -DLINUX -Dlinux -D_POSIX_SOURCE -D_BSD_SOURCE-DXP_UNIX -DDEBUG -UNDEBUG -DDEBUG_yahel -D_REENTRANT -I../../../../dist/Linux2.4_x86_glibc_PTH_DBG.OBJ/include -I../../../../dist/public/nss -I../../../../dist/private/nss Linux2.4_x86_glibc_PTH_DBG.OBJ/server.o Linux2.4_x86_glibc_PTH_DBG.OBJ/sslsample.o ../../../../dist/Linux2.4_x86_glibc_PTH_DBG.OBJ/lib/libsectool.a -Wl,-rpath,'$ORIGIN/../lib' -Wl,-rpath-link,../../../../dist/Linux2.4_x86_glibc_PTH_DBG.OBJ/lib -L../../../../dist/Linux2.4_x86_glibc_PTH_DBG.OBJ/lib -lssl3 -lsmime3 -lnss3 -L../../../../dist/Linux2.4_x86_glibc_PTH_DBG.OBJ/lib -lplc4 -lplds4 -lnspr4 -lpthread -ldl -lc

We didn't write good stand-alone makefiles for SSLsample.
Instead, SSLsample's makefiles include common makefiles that
we use to build NSS itself.  This is why you see a lot of
configuration macros on the compiler command line, that are
not really necessary for an application that uses NSS.  Sorry
about the confusion.

To compile NSS, you just need to use the platform-dependent
flags for compiling a multithreaded application.  This flag
is usually called -pthread or -pthreads on Unix platforms.
This requirement is actually for the NSPR library, which NSS
depends on.

As a reference, here are the flags we use to compile and link
an application that uses NSS on Linux:

$ nss-config --cflags
-I/usr/include/nss3
$ nss-config --libs
-Wl,-rpath-link,/usr/lib -L/usr/lib -lssl3 -lsmime3 -lnss3

You should replace /usr/include/nss3 and /usr/lib by the directories
where you installed the NSS headers and libraries.

Similarly the flags for an application that uses NSPR on Linux:

$ nspr-config --cflags
-I/usr/include/nspr4
$ nspr-config --libs
-L/usr/lib -lplds4 -lplc4 -lnspr4 -lpthread -ldl


Yes, it seems that an application does not need any specific library or -D flag, except -pthread. I used just that, and my applications had no trouble yet.

2.
How can I build using only static libraries?

This is no longer possible.  You can get very close, by
imitating how we build the commands in mozilla/security/nss/cmd/xxx
where we set USE_STATIC_LIBS=1 in the manifest.mn file.  But even
in that case, you still need the shared library libfreebl3.so, so
it's not 100% static libraries.
(On some Unix platforms we have multiple libfreebl_xxx_3.so's, one
for each version of the processor.)
Note that we discourage the use of NSS static libraries and don't
officially support it.


OK.

3.
How should an application generate error strings? The examples at SSLsample do a very strange trick. On the other hand, selfserv on my machine simply finds no error string (for example, when using a bad certificate database, error "-8174").

I'm afraid that right now each application needs to build its own
NSS error string table.  You can use the error string table for the
NSS command-line tools as an example:

http://lxr.mozilla.org/security/source/security/nss/cmd/lib/secerror.c


I see. Actually, this is what SSLsample does.

4.
It is explained that we can either configure a listen socket for SSL using SSL_ConfigSecureServer(), or listen in the regular manner and then configure enable SSL on the socket created by PR_Accept(). Is SSL_ConfigSecureServer() just an elegant way to enable SSL on all sockets created from some listen socket, and nothing else? Does it add any security?

I'll let Nelson answer this question.


OK

5.
Is there a simple example of an NSS client and server? I understand that the SSLsample example are not considered good enough. However, selfserv and strsclnt are rather complicated, since they handle numerous configuration options.

Unfortunately no.

Anyone have a simple NSS client and server?


I have written a simplistic client and server,
based on SSLsample and selfserv/strsclnt.
You are welcome to use it if you find it useful.

6.
bug report - in function setupSSLSocket() of SSLsample/client.c, any failure leads to closing tcpSocket, even after SSL_ImportFD(), which replaces tcpSocket by sslSocket.

Thank you for the bug report.  Would you have time to file it in
bugzilla.mozilla.org?  If not, I can do it for you.

Wan-Teh


I am not sure there is a bug here, since Nelson disagrees (see his message).

Yahel.
#include <plgetopt.h>
#include <nspr.h>
#include <nss.h> 
#include <pk11pub.h>
#include <ssl.h>
#include <sslproto.h>
#include <key.h>

static char *s_progName = NULL;

static void
errWarn(char * funcString)
{
    PRErrorCode perr = PR_GetError();
    fprintf(stderr, "%s: %s returned error %d\n", s_progName, funcString, perr);
    return;
}

static void
errExit(char * funcString)
{
    errWarn(funcString);
    exit(3);
}

static void
Usage(const char *progName)
{
        fprintf(stderr, "Usage: %s -n cert_name -p port -w password [-d 
cert_dir] \n", progName);
        exit(1);
}

/* fakePasswd()
 * 
 * This function is our custom password handler that is called by
 * SSL when retreiving private certs and keys from the database. Returns a
 * pointer to a string that with a password for the database. Password pointer
 * should point to dynamically allocated memory that will be freed later.
 * We set "arg" to give the correct password, using SSL_SetPKCS11PinArg().
 */
char *
fakePasswd(PK11SlotInfo *info, PRBool retry, void *arg)
{
        char * passwd = NULL;

        if ((!retry) && (arg != NULL)) {
                passwd = PL_strdup((char *)arg);
        }

        return passwd;
}


/* Function:  setupSSLSocket()
 *
 * Purpose:  Configure a socket for SSL.
 * NSS has 3 methods for configuring a TCP socket for SSL:
 * 1. Do the configuration step by step.
 * 2. Inherit a model socket using SSL_ImportFD.
 * 3. Do the configuration on the listen socket. This way,
 *    sockets created by PR_Accept inherit the configuration.
 *
 * - this application uses method 3, so we configure the listen socket.
 */
PRFileDesc * 
setupSSLSocket(PRFileDesc *tcpSocket,     
               CERTCertificate *cert,
               SECKEYPrivateKey *privKey,
               SSLKEAType sslKEA,
               char* password)
{
        PRFileDesc *sslSocket;
        SECStatus   secStatus;

        sslSocket = SSL_ImportFD(NULL, tcpSocket);
        if (sslSocket == NULL) {
                errWarn("SSL_ImportFD");
        PR_Close(tcpSocket);
        return NULL;
        }
   
    // ensure original socket is not used
    tcpSocket = NULL;

    do {
            
        // handshake as server
        secStatus = SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_SERVER, PR_TRUE);
        if (secStatus != SECSuccess) {
                errWarn("SSL_OptionSet:SSL_HANDSHAKE_AS_SERVER");
                break;
        }
    
        // enable full duplex
        secStatus = SSL_OptionSet(sslSocket, SSL_ENABLE_FDX, PR_TRUE);
        if (secStatus != SECSuccess) {
            errWarn("SSL_OptionSet(SSL_ENABLE_FDX)");
            break;
        }
    
        // allow communication without encryption (YZ - must be only upon 
client request)
        if (SECSuccess != SSL_CipherPrefSet(sslSocket, SSL_RSA_WITH_NULL_SHA, 
PR_TRUE)
            || SECSuccess != SSL_CipherPrefSet(sslSocket, 
SSL_RSA_WITH_NULL_MD5, PR_TRUE)) {
            errWarn("SSL_CipherPrefSet - Null Cipher");
            break;
        }
    
        /* // optional, see SSL reference.                                      
                  */
        /* secStatus = SSL_AuthCertificateHook(sslSocket, myAuthCertificate, 
CERT_GetDefaultCertDB()); */
        /* if (secStatus != SECSuccess) {                                       
                       */
        /*     errWarn("SSL_AuthCertificateHook");                              
                       */
        /*     break;                                                           
                       */
        /* }                                                                    
                       */
    
        /* // optional, see SSL reference.                                      
  */
        /* secStatus = SSL_BadCertHook(sslSocket,                               
       */
        /*                             (SSLBadCertHandler)myBadCertHandler, 
&certErr); */
        /* if (secStatus != SECSuccess) {                                       
       */
        /*     errWarn("SSL_BadCertHook");                                      
       */
        /*     break;                                                           
       */
        /* }                                                                    
       */
    
        /* // optional, see SSL reference.                                      
  */
        /* secStatus = SSL_HandshakeCallback(sslSocket,                         
       */
        /*                                  
(SSLHandshakeCallback)myHandshakeCallback, */
        /*                                   NULL);                             
       */
        /* if (secStatus != SECSuccess) {                                       
       */
        /*     errWarn("SSL_HandshakeCallback");                                
       */
        /*     break;                                                           
       */
        /* }                                                                    
       */
    
        secStatus = SSL_SetPKCS11PinArg(sslSocket, password);
        if (secStatus != SECSuccess) {
                errWarn("SSL_HandshakeCallback");
                break;
        }
    
        secStatus = SSL_ConfigSecureServer(sslSocket, cert, privKey, sslKEA);
        if (secStatus != SECSuccess) {
                errWarn("SSL_ConfigSecureServer");
                break;
        }
    
        // Success
        return sslSocket;

    } while (0);

    // Failure
        PR_Close(sslSocket);
        return NULL;
}

/* Function:  handleConnection()
 *
 * Purpose:  handle a single SSL connection.
 *
 */
SECStatus
handleConnection(PRFileDesc *sslSocket)
{
        PRStatus            prStatus;
        PRSocketOptionData  socketOption;
    char                buffer[256];
    PRInt32             rv;
        
    // ensure the socket is blocking. this should be the default.
        socketOption.option = PR_SockOpt_Nonblocking;
        socketOption.value.non_blocking = PR_FALSE;
        PR_SetSocketOption(sslSocket, &socketOption);

    /* // handshake as server - required in addition to the SSL option,   */
    /* // in case the listen socket was not an SSL socket.                */
    /* secStatus = SSL_ResetHandshake(sslSocket, PR_TRUE );               */
    /* if (secStatus != SECSuccess) {                                     */
    /*     errWarn("SSL_ResetHandshake");                                 */
    /*     return secStatus;                                              */
    /* }                                                                  */


    // use socket: single read, then single write

    rv = PR_Read(sslSocket, buffer, sizeof(buffer));
    // (rv == 0) is EOF
    if (rv <= 0) {
        errWarn("PR_Read");
        PR_Close(sslSocket);
        return SECFailure;
    }
    
    buffer[rv] = 0;
    printf("server received: %s \n", buffer);

    sprintf(buffer, "hello from server");
    int msgSize = strlen(buffer);

    rv = PR_Write(sslSocket, buffer, msgSize);
    if (rv != msgSize) {
        errWarn("PR_Write");
        PR_Close(sslSocket);
        return SECFailure;
    }
    
    printf("server sent: %s \n", buffer);
    
    // Finally 
    // -------

    printf("\n" "Closing client connection.\n");
        
    prStatus = PR_Close(sslSocket);
        if (prStatus != PR_SUCCESS) {
                errWarn("PR_Close");
                return SECFailure;
        }

        return SECSuccess;

}

/* Function: startListening()
 * 
 * Purpose: Create a new socket and starts listening.
 */

PRFileDesc *
startListening(unsigned short port)
{
    PRFileDesc *       listen_sock;
    PRStatus           prStatus;
    PRNetAddr          addr;
    PRSocketOptionData opt;

    addr.inet.family = PR_AF_INET;
    addr.inet.ip     = PR_INADDR_ANY;
    addr.inet.port   = PR_htons(port);

    listen_sock = PR_NewTCPSocket();
    if (listen_sock == NULL) {
        errExit("PR_NewTCPSocket");
    }

    // YZ set blocking mode. this should be the default anyway.
    opt.option = PR_SockOpt_Nonblocking;
    opt.value.non_blocking = PR_FALSE;
    prStatus = PR_SetSocketOption(listen_sock, &opt);
    if (prStatus < 0) {
        errExit("PR_SetSocketOption(PR_SockOpt_Nonblocking = PR_FALSE)");
    }

    opt.option=PR_SockOpt_Reuseaddr;
    opt.value.reuse_addr = PR_TRUE;
    prStatus = PR_SetSocketOption(listen_sock, &opt);
    if (prStatus < 0) {
        errExit("PR_SetSocketOption(PR_SockOpt_Reuseaddr = PR_TRUE)");
    }

    prStatus = PR_Bind(listen_sock, &addr);
    if (prStatus < 0) {
        errExit("PR_Bind");
    }

    prStatus = PR_Listen(listen_sock, 5);
    if (prStatus < 0) {
        errExit("PR_Listen");
    }
    
    return listen_sock;
}

/* Function: serverMain()
 *
 * Purpose: 
 * Loop to accept connections. For every connection, 
 * receive a message and then send a reply message.
 * Since listenSocket is an SSL socket, tcpSocket is an SSL socket too.
 */
void
serverMain(PRFileDesc *listenSocket)
{
        PRNetAddr   addr;
        PRStatus    prStatus;
    
        while (1) {
                PRFileDesc *tcpSocket;

                printf("\n" "Waiting for new connection.\n");

                /* Accept a connection */
                tcpSocket = PR_Accept(listenSocket, &addr, 
PR_INTERVAL_NO_TIMEOUT);
                if (tcpSocket == NULL) {
                        errWarn("PR_Accept");
                        break;
                }

                // Handle one connection at a time.
        // Can be replaced with a new thread
                handleConnection(tcpSocket);
        }

        printf("\n" "Closing listen socket.\n");

        prStatus = PR_Close(listenSocket);
        if (prStatus != PR_SUCCESS) {
                errWarn("PR_Close");
        }

        return;
}

int
main(int argc, char **argv)
{
        char *              password      = NULL;
        char *              certName      = NULL;
        char *              certDir       = ".";
        char *              cipherString  = NULL;
        unsigned short      port          = 0;
        PLOptState *        optstate;
        PLOptStatus         status;
        SECStatus           secStatus;
    CERTCertificate    *cert = NULL;
        SSLKEAType          sslKEA;
    SECKEYPrivateKey   *privKey = NULL;
    PRFileDesc *        listenSocket;
    PRFileDesc *        sslSocket;

        s_progName = argv[0];

        optstate = PL_CreateOptState(argc, argv, "c:d:p:n:w:");
        while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
                switch(optstate->option) {
                case 'c': cipherString = PL_strdup(optstate->value);    break;
                case 'd': certDir = PL_strdup(optstate->value);         break;
                case 'n': certName = PL_strdup(optstate->value);        break;
                case 'p': port = atoi(optstate->value);                 break;
                case 'w': password = PL_strdup(optstate->value);        break;
                case 0:                                                 break;
                case '?': Usage(s_progName);                            break;
        default:  Usage(s_progName);                            break;          
  
                }
        }

        if (certName == NULL || password == NULL || port == 0) {
        Usage(s_progName);
    }
    

    // Server set up
    // -------------

    PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
    
    PK11_SetPasswordFunc(fakePasswd);
    
    secStatus = NSS_Init(certDir);
    if (secStatus != SECSuccess) {
        errExit("NSS_Init");
    }

    // Using export policy.    
        secStatus = NSS_SetExportPolicy();
        if (secStatus != SECSuccess) {
                errExit("NSS_SetExportPolicy");
        }
    
        /* Get own certificate and private key. */
        cert = PK11_FindCertFromNickname(certName, password);
        if (cert == NULL) {
                errExit("PK11_FindCertFromNickname");
        }

    sslKEA = NSS_FindCertKEAType(cert);
    if (sslKEA == kt_null) {
        errExit("NSS_FindCertKEAType");
    }

        privKey = PK11_FindKeyByAnyCert(cert, password);
        if (privKey == NULL) {
                errExit("PK11_FindKeyByAnyCert");
        }
    // Set a session cache for single-process server.
    secStatus = SSL_ConfigServerSessionIDCache(100, 0, 0, 0);
    if (secStatus != SECSuccess) {
        errExit("SSL_ConfigServerSessionIDCache");    
    }
    
    listenSocket = startListening(port);
    if (listenSocket == NULL) {
        errExit("startListening");
    }

    sslSocket = setupSSLSocket(listenSocket, cert, privKey, sslKEA, password);
    if (sslSocket == NULL) {
        errExit("setupSSLSocket");
    }
        
    // Main server loop
    // ----------------

    serverMain(sslSocket);
    

    // Server shutdown
    // ---------------

    if (cert) {
        CERT_DestroyCertificate(cert);
    }
    
    if (privKey) {
        SECKEY_DestroyPrivateKey(privKey);
    }

    SSL_ShutdownServerSessionIDCache();

    if (NSS_Shutdown() != SECSuccess) {
        errExit("NSS_Shutdown");
    }

    PR_Cleanup();
    
    if (certName) {
        free(certName);
    }

    if (certDir) {
        free(certDir);
    }

    if (password) {
        free(password);
    }
   
    printf("%s: normal termination\n", s_progName);
    return 0;
}
M_ROOT=/usr/home/yahel/programs/nss/mozilla

M_DIST=${M_ROOT}/dist/Linux2.4_x86_glibc_PTH_DBG.OBJ

M_INC=-I${M_DIST}/include -I${M_ROOT}/dist/public/nss


M_FLAGS = -g -Wall
M_LIBS = -L${M_DIST}/lib -lssl3 -lnss3 -lnspr4

all: server client
        @echo done
        
clean:
        rm -f client server client.o server.o

server.o: server.c
        gcc -c ${M_FLAGS} ${M_INC} server.c -o server.o

client.o: client.c
        gcc -c ${M_FLAGS} ${M_INC} client.c -o client.o

server: server.o
        gcc ${M_FLAGS} ${M_INC} ${M_LIBS} server.o -o server

client: client.o
        gcc ${M_FLAGS} ${M_INC} ${M_LIBS} client.o -o client
#include <plgetopt.h> 
#include <nspr.h>
#include <nss.h> 
#include <pk11pub.h>
#include <ssl.h> 
#include <sslproto.h>
#include <key.h>

static char *s_progName = NULL;
static char *s_password = NULL;
static char *s_hostName = NULL;

static void
errWarn(char * funcString)
{
    PRErrorCode prError = PR_GetError();
    
    fprintf(stderr, "%s: %s returned %d\n", s_progName, funcString,  prError);
    return;
}

static void
errExit(char * funcString)
{
    errWarn(funcString);
    exit(3);
}

static void
Usage(const char *progName)
{
        fprintf(stderr, "Usage: %s hostname -n cert_name -p port -d cert_dir -w 
password \n", progName);
        exit(1);
}

/* myPasswd()
 * 
 * This function is our custom password handler that is called by
 * SSL when retreiving private certs and keys from the database. Returns a
 * pointer to a string that with a password for the database. Password pointer
 * should point to dynamically allocated memory that will be freed later.
 * We set "arg" to give the correct password, using SSL_SetPKCS11PinArg().
 */
char *
fakePasswd(PK11SlotInfo *info, PRBool retry, void *arg)
{
        char * passwd = NULL;

        if ((!retry) && (arg != NULL)) {
                passwd = PL_strdup((char *)arg);
        }

        return passwd;
}


/* Function:  setupSSLSocket()
 *
 * Purpose:  Configure a socket for SSL.
 */
PRFileDesc * 
setupSSLSocket()
{
        PRFileDesc         *sslSocket;
        PRFileDesc         *tcpSocket;
        SECStatus           secStatus;
        PRSocketOptionData      socketOption;
        PRStatus            prStatus;

    tcpSocket = PR_NewTCPSocket();
    if (tcpSocket == NULL) {
        errWarn("PR_NewTCPSocket");
        return NULL;
    }
    
    // Ensure the socket is blocking.
    socketOption.option             = PR_SockOpt_Nonblocking;
    socketOption.value.non_blocking = PR_FALSE;
    
    prStatus = PR_SetSocketOption(tcpSocket, &socketOption);
    if (prStatus != PR_SUCCESS) {
        errWarn("PR_SetSocketOption");
        PR_Close(tcpSocket);
        return NULL;
    } 

        sslSocket = SSL_ImportFD(NULL, tcpSocket);
        if (sslSocket == NULL) {
                errWarn("SSL_ImportFD");
        PR_Close(tcpSocket);
        return NULL;
        }
    
    // ensure original socket is not used
    tcpSocket = NULL;

    do {
            
        // handshake as client
        secStatus = SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
        if (secStatus != SECSuccess) {
                errWarn("SSL_OptionSet:SSL_HANDSHAKE_AS_CLIENT");
                break;
        }
    
        // enable full duplex
        secStatus = SSL_OptionSet(sslSocket, SSL_ENABLE_FDX, PR_TRUE);
        if (secStatus != SECSuccess) {
            errWarn("SSL_OptionSet(SSL_ENABLE_FDX)");
            break;
        }
    
        // allow communication without encryption (YZ - must be only upon 
client request)
        if (SECSuccess != SSL_CipherPrefSet(sslSocket, SSL_RSA_WITH_NULL_SHA, 
PR_TRUE)
            || SECSuccess != SSL_CipherPrefSet(sslSocket, 
SSL_RSA_WITH_NULL_MD5, PR_TRUE)) {
            errWarn("SSL_CipherPrefSet - Null Cipher");
            break;
        }
        
        secStatus = SSL_SetPKCS11PinArg(sslSocket, s_password);
        if (secStatus != SECSuccess) {
                errWarn("SSL_SetPKCS11PinArg");
                break;
        }
    
        secStatus = SSL_SetURL(sslSocket, s_hostName);
        if (secStatus != SECSuccess) {
            errWarn("SSL_SetURL");
            break;
        }
        
        // Success
        return sslSocket;

    } while (0);

    // Failure
        PR_Close(sslSocket);
        return NULL;
}

/* Function:  clientMain()
 *
 * Purpose:  Setup an SSL socket and connect a server.
 *           Send a small message and expect a reply message.
 */
void
clientMain(unsigned short port)
{
        SECStatus       secStatus;
        PRStatus    prStatus;
        PRInt32     rv;
        PRNetAddr       addr;
        PRHostEnt   hostEntry;
    PRFileDesc *sslSocket;
        char        buffer[256];

    sslSocket = setupSSLSocket();
    if (sslSocket == NULL) {
                errExit("setupSSLSocket");
    }

        prStatus = PR_GetHostByName(s_hostName, buffer, sizeof(buffer), 
&hostEntry);
        if (prStatus != PR_SUCCESS) {
                errExit("PR_GetHostByName");
        }

        rv = PR_EnumerateHostEnt(0, &hostEntry, port, &addr);
        if (rv < 0) {
                errExit("PR_EnumerateHostEnt");
        }

    prStatus = PR_Connect(sslSocket, &addr, PR_INTERVAL_NO_TIMEOUT);
    if (prStatus != PR_SUCCESS) {
        errExit("PR_Connect");
    }
       
    secStatus = SSL_ResetHandshake(sslSocket, /* asServer */ PR_FALSE);
    if (secStatus != SECSuccess) {
        errExit("SSL_ResetHandshake");
    }
    
    // single write, then single read

    sprintf(buffer, "hello from client");
    int msgSize = strlen(buffer);

    rv = PR_Write(sslSocket, buffer, msgSize);
    if (rv != msgSize) {
        errWarn("PR_Write");
        PR_Close(sslSocket);
        return;
    }
    
    printf("client sent: %s \n", buffer);
    
    rv = PR_Read(sslSocket, buffer, sizeof(buffer));
    // (rv == 0) is EOF
    if (rv <= 0) {
        errWarn("PR_Read");
        PR_Close(sslSocket);
        return;
    }
    
    buffer[rv] = 0;
    printf("client received: %s \n", buffer);
        
    prStatus = PR_Close(sslSocket);
    if (prStatus != PR_SUCCESS) {
        errExit("PR_Close");
    }

    return;
}

int
main(int argc, char **argv)
{
        char *              certName      = NULL;
        char *              certDir       = ".";
        unsigned short      port          = 0;
        PLOptState *        optstate;
        PLOptStatus         status;
        SECStatus           secStatus;

        s_progName = argv[0];

        optstate = PL_CreateOptState(argc, argv, "d:p:n:w:");
        while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
                switch(optstate->option) {
                case 0:   s_hostName = PL_strdup(optstate->value);      break;
                case 'd': certDir = PL_strdup(optstate->value);         break;
                case 'n': certName = PL_strdup(optstate->value);        break;
                case 'p': port = atoi(optstate->value);                 break;
                case 'w': s_password = PL_strdup(optstate->value);      break;
        case '?': Usage(s_progName);                            break;
        default:  Usage(s_progName);                            break;          
  
                }
        }

        if (certName == NULL || s_hostName == NULL || s_password == NULL || 
port == 0) {
        Usage(s_progName);
    }
    

    // Client set up
    // -------------

    PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);

    PK11_SetPasswordFunc(fakePasswd);
    
    secStatus = NSS_Init(certDir);
    if (secStatus != SECSuccess) {
        errExit("NSS_Init");
    }

        secStatus = NSS_SetExportPolicy();
        if (secStatus != SECSuccess) {
                errExit("NSS_SetExportPolicy");
        }
        
    // optional - clear client cache
    SSL_ClearSessionCache();
    

    // Client main function
    // --------------------

    clientMain(port);
    

    // Client shutdown
    // ---------------

    SSL_ClearSessionCache(); // otherwise, NSS_Shutdown fails.
    if (NSS_Shutdown() != SECSuccess) {
        errExit("NSS_Shutdown"); 
    }

    PR_Cleanup();
    
    if (certName) {
        free(certName);
    }

    if (certDir) {
        free(certDir);
    }

    if (s_hostName) {
        free(s_hostName);
    }

    printf("%s: normal termination\n", s_progName);
    return 0;
}
_______________________________________________
dev-tech-crypto mailing list
dev-tech-crypto@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-tech-crypto

Reply via email to