Milán Major

netscape-revival

1 branch
Code

security/lib/nav/fortdlgs.c

/*
 * Fortezza Security stuff specific to the client (mozilla).
 *
 * Copyright © 1995 Netscape Communications Corporation, all rights reserved.
 *
 * $Id: fortdlgs.c,v 1.5.26.1 1997/05/03 09:25:06 jwz Exp $
 */

#include "cert.h"
#include "net.h"
#include "xp.h"
#include "../cert/certdb.h"
#include "../ssl/sslimpl.h"
#include "htmldlgs.h"
#include "sslproto.h"
#include "sslerr.h"
#include "../crypto/fortezza.h"
#include "fortdlgs.h"
#include "ssl.h"
#include "prmem.h"
#include "xpgetstr.h"
#include "prtime.h"

extern FortezzaGlobal fortezzaGlobal;
extern int XP_ERRNO_EWOULDBLOCK;
extern int XP_SELECT_FORTEZZA_CARD;
extern int XP_SELECT_FORTEZZA_PERSONALITY;
extern int XP_SHOW_FORTEZZA_PERSONALITY;
extern int XP_SHOW_FORTEZZA_CARD_INFO;
extern int XP_PLAIN_CERT_DIALOG_STRINGS;
extern int XP_SEC_FORTEZZA_NO_CARD;
extern int XP_SEC_FORTEZZA_NONE_SELECTED;
extern int XP_SEC_FORTEZZA_MORE_INFO;
extern int XP_SEC_FORTEZZA_PERSON_NOT_FOUND;
extern int XP_SEC_FORTEZZA_NO_MORE_INFO;
extern int XP_SEC_FORTEZZA_BAD_PIN;
extern int XP_SEC_FORTEZZA_PERSON_ERROR;
extern int XP_SEC_FORTEZZA_NO_CERT;
extern int XP_SEC_FORTEZZA_SOCKET;
extern int XP_SEC_FORTEZZA_SERIAL;
extern int XP_SEC_FORTEZZA_EMPY;
extern int XP_SEC_FORTEZZA_LOGIN;
extern int XP_SEC_FORTEZZA_LOGOUT;
extern int XP_SEC_FORTEZZA_INIT;
extern int XP_FORTEZZA_CHOOSE_CARD;
extern int XP_FORTEZZA_CHOOSE_PERSONALITY;
extern int XP_FORTEZZA_VIEW_PERSONALITY;
extern int XP_FORTEZZA_PERSONALITY;
extern int XP_FORTEZZA_CARD_INFO;


/*
 * Dialog Helper routines... Stold from certdlg.c
 */


/*
 * Add a socket to the linked list of sockets waiting for client auth to
 * be approved by the user for the certificate.
 */
static SECStatus
AddSockToGlobal(SSLSocket *ss)
{
    SECSocketNode *node;
    
    node = PORT_ZAlloc(sizeof(SECSocketNode));
    if ( node ) {
	node->ss = ss;
	node->next = fortezzaGlobal.sslList;
	fortezzaGlobal.sslList = node;

	ss->dialogPending = PR_TRUE;
	
	return(SECSuccess);
    }

    return(SECFailure);
}

/*
 * Handshake function that blocks.  Used to force a
 * retry on a connection on the next read/write.
 */
static int
AlwaysBlock(SSLSocket *ss)
{
    PORT_SetError(XP_ERRNO_EWOULDBLOCK);
    return -2;
}

/*
 * set the handshake to block
 */
static void
SetAlwaysBlock(SSLSocket *ss)
{
    ss->handshake = AlwaysBlock;
    ss->nextHandshake = 0;
    return;
}

static void
FortezzaMarkSocketWait(SSLSocket *ss) {
    AddSockToGlobal(ss);
    SetAlwaysBlock(ss);

    PORT_SetError(XP_ERRNO_EWOULDBLOCK);
}

SECSocketNode *
FreeNode(SECSocketNode *np) {
    SECSocketNode *next = np->next;

    PORT_Free(np);
    return next;
}

static void
RestartOpen(PRBool restart) {
    SECSocketNode *node;
    SSLSocket *ss;
    SECStatus rv;

    if (!restart) fortezzaGlobal.state = GlobalSkip;

    for (node = fortezzaGlobal.sslList;  node; node = FreeNode(node)) {
	if (fortezzaGlobal.sslList) fortezzaGlobal.sslList = NULL;
	ss = node->ss;

	if ( ss->beenFreed ) {
	    ssl_FreeSocket(ss);
	    continue;
	}

	ss->dialogPending = PR_FALSE;

	rv = SSL_RestartHandshakeAfterFortezza(ss);
	if (rv == SECFailure) {
	    NET_InterruptSocket(ss->fd);
	}
    }

    fortezzaGlobal.state = GlobalOK;
}

/*
 * Family of routines to support choosing a card
 */
/* (OK only the Serial: and the Socket).  */
#define OPTION_STR "<option>"
#define SELECT_STR " selected"
#define OPTIONSEL_STR "<option selected>"
#define OPTION_STR_LEN (sizeof(OPTION_STR)-1)
#define SELECT_STR_LEN (sizeof(SELECT_STR)-1)
#define OPTIONSEL_STR_LEN (sizeof(OPTIONSEL_STR)-1)
#define SERIAL_STR "</b> Serial: "
#define SERIAL_STR_LEN (sizeof(SERIAL_STR)-1)
/* Some of following strings need to be internationalizes! */
static char *card_states[] = {
    (char *)0, (char *)0, (char *)0, (char *)0
};

static int max_state_len = 0;

static char itoh(int x) {
   x &= 0xf;
   if (x > 9) return x + 'a' - 10;
   return x + '0';
}

static PRBool
fortezzaChooseCardDialogHandler(XPDialogState *state, char **argv, int argc,
					unsigned int button) {
    fortezzaGlobal.state = GlobalOK;
    if (button == XP_DIALOG_OK_BUTTON) {
	char *cardname = XP_FindValueInArgs("cards", argv, argc);
	char *cp;
	unsigned int socket = 0;

	/*
	 * lots of magic numbers below. We are extracting '_Socket_nn'
	 * on the 'nn' is of interest to use, all the rest was info for
	 * the user...
 	 */
	for (cp=cardname; *cp; cp++) {
	    if ((*cp >= '0') || (*cp <= '9')) {
		break;
	    }
	}
	socket = atoi(cp);

	socket -= 1; /* convert from socket number */

	/* do an unsigned compare in case socket is negative */
	if (socket < (unsigned)fortezzaGlobal.socketCount) {
	    FortezzaPCMCIASocket *psock=&fortezzaGlobal.sockets[socket];
	    if (psock->state != NoCard) {
		fortezzaGlobal.defaultSocket = psock;
		RestartOpen(PR_TRUE);
		return PR_FALSE;
	    }
	}
    }
    RestartOpen(PR_FALSE);
    return PR_FALSE;
}


	
 
static XPDialogInfo fortezzaChooseCardDialog = {
    XP_DIALOG_OK_BUTTON | XP_DIALOG_CANCEL_BUTTON,
    fortezzaChooseCardDialogHandler,
    450,
    250
};


#define MAX_CARDS 32
SECStatus
FortezzaChooseCard(MWContext *cx,FortezzaCardInfo *info,uint32 mask,
								int count) {
	XPDialogStrings *strings;
	char *cards,*tmp;
	int i,j,len;
	char *sock_name = PORT_Strdup(XP_GetString(XP_SEC_FORTEZZA_SOCKET));
	int sock_len = PORT_Strlen(sock_name);
	char *serial_name = PORT_Strdup(XP_GetString(XP_SEC_FORTEZZA_SERIAL));
	int serial_len = PORT_Strlen(serial_name);

	if (mask == 0) {
	     /* FE_Alert */	
	     FE_Alert(cx,XP_GetString(XP_SEC_FORTEZZA_NO_CARD));
    	     fortezzaGlobal.state = GlobalOK;
	     PORT_Free(sock_name);
	     PORT_Free(serial_name);
	     return SECFailure;
	}
	if (max_state_len == 0) {
	    int i=0;

	    card_states[i++] = PORT_Strdup(XP_GetString(XP_SEC_FORTEZZA_EMPY));
	    card_states[i++] = PORT_Strdup(XP_GetString(XP_SEC_FORTEZZA_LOGIN));
	    card_states[i++] = PORT_Strdup(XP_GetString(XP_SEC_FORTEZZA_LOGOUT));
	    card_states[i++] = PORT_Strdup(XP_GetString(XP_SEC_FORTEZZA_INIT));

	    for(i=0; i < 4; i++) {
		int l = PORT_Strlen(card_states[i]);

		if (l > max_state_len) max_state_len = l;
	    }
	}

	strings = XP_GetDialogStrings(XP_SELECT_FORTEZZA_CARD);
	cards = tmp = (char *) PORT_Alloc(count * 
		(OPTION_STR_LEN + sock_len + 3/* sock_no */ +
	   	max_state_len + serial_len + 20) + SELECT_STR_LEN+10);
	for (i=0; i < count; i++) {
	    char sock_no[10];
	    char serial[16];

	    int socket = i+1;
	    if (mask & (1<<i)) {
		if (fortezzaGlobal.defaultSocket && 
			   fortezzaGlobal.defaultSocket->socketId == socket) { 
	        	PORT_Memcpy(tmp, OPTIONSEL_STR, OPTIONSEL_STR_LEN );
			tmp += OPTIONSEL_STR_LEN;
		} else {
	        	PORT_Memcpy(tmp, OPTION_STR, OPTION_STR_LEN );
			tmp += OPTION_STR_LEN;
		}
	       	PORT_Memcpy(tmp, sock_name, sock_len );
		tmp += sock_len;
		PR_snprintf(sock_no,sizeof(sock_no),"%d <b>",socket);
		len = PORT_Strlen(sock_no);
		PORT_Memcpy(tmp,sock_no,len);	
		tmp += len;
		len = PORT_Strlen(card_states[info[i].state]);
		PORT_Memcpy(tmp,card_states[info[i].state],len);	
		tmp +=len;
		/* someday we should build a data base between serial
		 * number and "primary" user cert names so the user
		 * has a little nicer info about the card they are using..
		 */
		PORT_Memcpy(tmp,serial_name,serial_len);
		tmp += serial_len;

		for (j=0; j < 8; j++) {
			unsigned char n = info[i].serial[j];
			serial[j*2] = itoh((n >> 4) & 0xf);
			serial[j*2+1] = itoh(n & 0xf);
		}
		PORT_Memcpy(tmp,serial,sizeof(serial));
		tmp += sizeof(serial);
	    }
	}
	*tmp = 0;
	XP_CopyDialogString(strings, 0, cards);
	PORT_Free(cards);

	XP_MakeHTMLDialog(cx,&fortezzaChooseCardDialog,
				 XP_FORTEZZA_CHOOSE_CARD,strings, NULL);
	XP_FreeDialogStrings(strings);
	PORT_Free(sock_name);
	PORT_Free(serial_name);
	return SECWouldBlock;
}

static int
fortezzaCertIndexByName(FortezzaPCMCIASocket *psock,char *personality,int len) {
	char **personalities;
	int *indexes;
	int maxCount, i;
	SECStatus rv;
	int index = -1;

	     
	rv = FortezzaLookupPersonality(psock, &personalities, &maxCount,
								&indexes);
	if (rv < 0) goto loser;

	for (i=0; i < maxCount; i++) {
	    if (PORT_Strncmp(personalities[i],personality,len) == 0) {
		index= indexes[i];
	    }
	}
	FortezzaFreePersonality(personalities);
	PORT_Free(indexes);
loser:
	return index;
}
/*
 * Family of routines to support choosing a personality
 */

static PRBool
fortezzaSelectPersonalityDialogHandler(XPDialogState *state, char **argv,
				 	     int argc, unsigned int button) {
    FortezzaPCMCIASocket *psock = fortezzaGlobal.defaultSocket;
    PRBool found = PR_FALSE;

    /* defensive... */
    fortezzaGlobal.state = GlobalOK;
    if ((psock == NULL) || (psock->state == NoCard)) {
	/* FE_ALER */
	goto loser;
    }

    if (button == XP_DIALOG_OK_BUTTON) {
	char *personality = XP_FindValueInArgs("personality", argv, argc);
	int index;

	index = fortezzaCertIndexByName(psock,personality,
						PORT_Strlen(personality));
	if (index > 0) {
		psock->template.certificate = index;
		psock->state = Ready;
		found = PR_TRUE;
	}
    }
loser:
    RestartOpen(found);
    return PR_FALSE;
}


	
 
static XPDialogInfo fortezzaSelectPersonalityDialog = {
    XP_DIALOG_OK_BUTTON | XP_DIALOG_CANCEL_BUTTON,
    fortezzaSelectPersonalityDialogHandler,
    450,
    250
};


SECStatus
FortezzaSelectPersonality(MWContext *cx,char **names, int count, int def_cert) {
	XPDialogStrings *strings;
	char *personalities,*tmp;
	int i,len;

	strings = XP_GetDialogStrings(XP_SELECT_FORTEZZA_PERSONALITY);

	len = 0;
	for (i=0 ; i < count; i++) {
	    len += PORT_Strlen(names[i]);
	}
	personalities = tmp = (char *) 
		PORT_Alloc(count*OPTION_STR_LEN+SELECT_STR_LEN+len+1);
	for (i=0; i < count; i++) {
	    if (i == def_cert) {
	    	PORT_Memcpy(tmp, OPTIONSEL_STR, OPTIONSEL_STR_LEN );
	    	tmp += OPTIONSEL_STR_LEN;
	    } else {
	    	PORT_Memcpy(tmp, OPTION_STR, OPTION_STR_LEN );
	        tmp += OPTION_STR_LEN;
	    }
	    len = PORT_Strlen(names[i]);
	    PORT_Memcpy(tmp,names[i],len);
	    tmp += len;
	}
	*tmp = 0;
	XP_CopyDialogString(strings, 0, personalities);
	PORT_Free(personalities);

	XP_MakeHTMLDialog(cx,&fortezzaSelectPersonalityDialog, 
			XP_FORTEZZA_CHOOSE_PERSONALITY, strings, NULL);
	XP_FreeDialogStrings(strings);
	return SECWouldBlock;
}

/*
 * Family of routines to support listing the personalities
 */
/* The following strings need to be internationalizes! */

static XPDialogInfo certDialog = {
	XP_DIALOG_OK_BUTTON,
	0,
	600,
	400
};

/* return true if the cert for this bit is set in the cert flags */
static PRBool
FortezzaCertBits(unsigned char *bits, int cert) {
	int bitIndex = cert >> 3; /* cert div 8 */
	int bitLoc = 0x80 >> (cert & 0x7); /* cert mod 8 */

	return ((bits[bitIndex] & bitLoc) == bitLoc);
}

static int
fortezzaAnyCertIndexByName(FortezzaPCMCIASocket *psock,char *personality,
								int len) {
	int i;
	int index = -1;
	CI_PERSON *pp = psock->personalityList;
	char *name;

	for (i=0; i < psock->certificateCount; i++) {
	    if (!FortezzaCertBits(psock->certFlags,i)) continue;
            name = (char *)&pp[i].CertLabel[8];
	    if (PORT_Strncmp(name,personality,len) == 0) {
		index = pp[i].CertificateIndex;
		break;
	    }
	}

	return index;
}

static PRBool
fortezzaShowPersonalityDialogHandler(XPDialogState *state, char **argv,
				 	     int argc, unsigned int button) {
    char *certstr;
    XPDialogStrings *strings;
    
    
    /* bring up the "More Info..." dialog, which gives detailed
     * certificate info.
     */
    if ( button == XP_DIALOG_MOREINFO_BUTTON ) {
	CERTCertificate *cert;
	char *personality = XP_FindValueInArgs("personality", argv, argc);
	int len,index; 
	MWContext *cx = (MWContext *)state->arg;
	FortezzaPCMCIASocket *psock = fortezzaGlobal.defaultSocket;

	if (personality == NULL) {
	    FE_Alert(cx,XP_GetString(XP_SEC_FORTEZZA_MORE_INFO));
	    return PR_TRUE;
	}

	/* find up to the first '(' */
	for (len=0;personality[len] && personality[len] != '(';len++); 

	index = fortezzaAnyCertIndexByName(psock,personality,len);
	if (index < 0) {
	    FE_Alert(cx, XP_GetString(XP_SEC_FORTEZZA_PERSON_NOT_FOUND));
	    return PR_FALSE;
	}
	cert = FortezzaGetCertificate(psock->socketId,index, psock->serial);
	if (cert == NULL) {
	    FE_Alert(cx,XP_GetString(XP_SEC_FORTEZZA_NO_MORE_INFO));
	    return PR_TRUE;
	}
	certstr = CERT_HTMLCertInfo(cert, PR_TRUE);

	strings = XP_GetDialogStrings(XP_PLAIN_CERT_DIALOG_STRINGS);
	if ( strings ) {
	    XP_SetDialogString(strings, 0, certstr);
	    XP_MakeHTMLDialog(cx, &certDialog, XP_FORTEZZA_PERSONALITY,
			      strings, 0);
	    XP_FreeDialogStrings(strings);
	}
	PORT_Free(certstr);
	CERT_DestroyCertificate(cert);
	return PR_TRUE;
    }
    
    return PR_FALSE;
}

static XPDialogInfo fortezzaShowPersonalityDialog = {
    XP_DIALOG_OK_BUTTON,
    fortezzaShowPersonalityDialogHandler,
    450,
    350
};


SECStatus
FortezzaShowPersonality(MWContext *cx,CI_PERSON *pp, int size, int count,
						unsigned char *certflags) {
	XPDialogStrings *strings;
	char *personalities,*tmp;
	int i,len;

	strings = XP_GetDialogStrings(XP_SHOW_FORTEZZA_PERSONALITY);

#define TABLE_SIZE (9 /*size of <option>'s */ + \
		24 /* pers name */ + 24 /* parent name */ + 40 /* type */)
	personalities = tmp = (char *) PORT_Alloc(count * TABLE_SIZE + 1);
	for (i=0; i < size; i++) {
	    int user = 0, kea = 0, sig = 0;
	    int j,index;
	    char *parent,*name, *typeName;
	    char type[5];

	    if (!FortezzaCertBits(certflags,i)) continue;
	    if (pp[i].CertLabel[0] == 0) continue;
	    if (pp[i].CertLabel[2] == 'K') {
		kea++; user++;
	    }
	    if (pp[i].CertLabel[3] == 'S') {
		sig++; user++;
	    }
	    name = (char *)&pp[i].CertLabel[8];
	    PORT_Memcpy(type,(char *)pp[i].CertLabel,4);
	    type[4] = 0;
	    index = atoi((char *)&pp[i].CertLabel[4]);

	    if ((pp[i].CertLabel[0] == 'I') && (pp[i].CertLabel[1] == 'N')) {
		typeName="Individual";
	    } else if ((pp[i].CertLabel[0] == 'O') &&
	       ((pp[i].CertLabel[1] == 'N') || (pp[i].CertLabel[1] == 'R'))) {
		typeName="Organization";
	    } else if ((pp[i].CertLabel[0] == 'R') && 
						(pp[i].CertLabel[1] == 'R')) {
		typeName="Policy Approval Authority";
	    } else if ((pp[i].CertLabel[0] == 'R') && 
						(pp[i].CertLabel[1] == 'T')) {
		typeName="Policy Creation Authority";
	    } else if ((pp[i].CertLabel[0] == 'L') && 
						(pp[i].CertLabel[1] == 'A')) {
		typeName="Certification Authority (CA)";
	    } else if ((pp[i].CertLabel[0] == 'S') && 
						(pp[i].CertLabel[1] == 'T')) {
		typeName="Secure Telephone Unit";
	    } else if ((pp[i].CertLabel[0] == 'F') && 
						(pp[i].CertLabel[1] == 'A')) {
		typeName="Fax Data";
	    } else {
		typeName=type;
	    }

	    if (index == 0) {
	    	parent = "PAA Root";
	    } else {
		parent = "unknown";
		for (j=0; j < count; j++) {
		    if (index == pp[j].CertificateIndex) {
			parent = (char *)&pp[j].CertLabel[8];
		    }
		}
	    }
	    len = PR_snprintf(tmp,TABLE_SIZE,
  		"<option>%s (%s)%s\n",name,typeName,user? "*": " ");
	    tmp += len;
	}
	*tmp = 0;
	XP_CopyDialogString(strings, 0, personalities);
	PORT_Free(personalities);

	XP_MakeHTMLDialog(cx,&fortezzaShowPersonalityDialog,
		XP_FORTEZZA_VIEW_PERSONALITY, strings, cx);
	XP_FreeDialogStrings(strings);
	return SECWouldBlock;
}
/*
 * Family of routines to support choosing a card
 */
/* The following strings need to be internationalizes! */

static PRBool
fortezzaCardInfoDialogHandler(XPDialogState *state, char **argv,
				 	     int argc, unsigned int button) {
    return PR_FALSE;
}


	
 
static XPDialogInfo fortezzaCardInfoDialog = {
    XP_DIALOG_OK_BUTTON,
    fortezzaCardInfoDialogHandler,
    450,
    370
};



#define MK_VERSION(x) \
      ((unsigned)(x)) >> 8, (((unsigned)(x)) >> 4) & 0xf, ((x)&0xf)
SECStatus
FortezzaShowCardInfo(MWContext *cx,FortezzaPCMCIASocket *psock) {
	XPDialogStrings *strings;
	CI_CONFIG config;
	CI_STATUS status;
	char serial[17];
	unsigned char *serialPtr;
	char *buf;
	char **personalities;
	int  *indexes;
	char *none_selected =
		PORT_Strdup(XP_GetString(XP_SEC_FORTEZZA_NONE_SELECTED));
	char *no_cert= PORT_Strdup(XP_GetString(XP_SEC_FORTEZZA_NO_CERT));
	int	rv,i,maxCount;
	int	next=0;
	int 	italic = 0;

	strings = XP_GetDialogStrings(XP_SHOW_FORTEZZA_CARD_INFO);

	/* deal with the socket number
	 * italicize the whole thing if we had any problems.
	 */
	rv = FortezzaGetConfig(psock,&config,&status);
	if (rv == SECSuccess) {
	    XP_CopyDialogString(strings, next, ""); next ++;
	} else {
	    XP_CopyDialogString(strings, next, "<i>"); next ++;
	     italic++;
	}
	     
	if (psock) {
	     buf = PR_smprintf("%d",psock->socketId);
	} else {
	     buf = PR_smprintf(none_selected);
	}
	XP_CopyDialogString(strings, next, buf); next ++;
	PR_DELETE(buf);

	/* deal with card state */
	if (psock) {
	    XP_CopyDialogString(strings, next,
					card_states[psock->state]); next++;
	} else {
	    XP_CopyDialogString(strings, next, none_selected); next++;
	}

	/* deal with card the serial number */
	if (psock) {
	    serialPtr = psock->serial;
	} else {
	    serialPtr = status.SerialNumber;
	}
	for (i=0; i < 8; i++) {
		unsigned char n = serialPtr[i];
		serial[i*2] = itoh((n >> 4) & 0xf);
		serial[i*2+1] = itoh(n & 0xf);
	}
	serial[16] = 0;
	XP_CopyDialogString(strings, next, serial); next ++;

	/* deal with card the user certificate */
	buf = no_cert;
	rv = SECFailure;
	if (psock && psock->state == Ready) {
	    rv = FortezzaLookupPersonality(psock, &personalities, &maxCount,
								&indexes);
	    if (rv == SECSuccess) {
		for (i=0; i < maxCount; i++) {
		    if (psock->template.certificate == indexes[i]) {
			buf = personalities[i];
			break;
		    }
	    	}
	    }
	}
	XP_CopyDialogString(strings, next, buf); next ++;
	if (rv == SECSuccess) {
	    FortezzaFreePersonality(personalities);
	    PORT_Free(indexes);
	}


	/* now deal with the config parameters */
	buf = PR_smprintf("%d.%d.%d", MK_VERSION(config.LibraryVersion));
	XP_CopyDialogString(strings, next, buf); next ++;
	PR_DELETE(buf);
	
	buf = PR_smprintf("%d.%d.%d", MK_VERSION(config.ManufacturerVersion));
	XP_CopyDialogString(strings, next, buf); next ++;
	PR_DELETE(buf);

	XP_CopyDialogString(strings, next, config.ManufacturerName); next ++;
	XP_CopyDialogString(strings, next, config.ProductName); next ++;
	XP_CopyDialogString(strings, next, config.ProcessorType); next ++;

	buf = PR_smprintf("%ld", config.UserRAMSize);
	XP_CopyDialogString(strings, next, buf); next ++;
	PR_DELETE(buf);

	buf = PR_smprintf("%ld", config.LargestBlockSize);
	XP_CopyDialogString(strings, next, buf); next ++;
	PR_DELETE(buf);

	buf = PR_smprintf("%d",config.KeyRegisterCount);
	XP_CopyDialogString(strings, next, buf); next ++;
	PR_DELETE(buf);

	buf = PR_smprintf("%d",config.CertificateCount);
	XP_CopyDialogString(strings, next, buf); next ++;
	PR_DELETE(buf);

	XP_CopyDialogString(strings, next, 
			config.CryptoCardFlag ? "on" : "off"); next ++;

	buf = PR_smprintf("%d.%d.%d", MK_VERSION(config.ICDVersion));
	XP_CopyDialogString(strings, next, buf); next ++;
	PR_DELETE(buf);

	buf = PR_smprintf("%d.%d.%d", MK_VERSION(config.ManufacturerSWVer));
	XP_CopyDialogString(strings, next, buf); next ++;
	PR_DELETE(buf);

	buf = PR_smprintf("%d.%d.%d%s", MK_VERSION(config.DriverVersion),
							italic?"</i>":" ");
	XP_CopyDialogString(strings, next, buf); next ++;
	PR_DELETE(buf);

	XP_MakeHTMLDialog(cx,&fortezzaCardInfoDialog,
					 XP_FORTEZZA_CARD_INFO,strings, NULL);
	XP_FreeDialogStrings(strings);
	PORT_Free(none_selected);
	PORT_Free(no_cert);
	return SECSuccess;
}

void
SSL_FortezzaMenu(MWContext *cx, int type) {
	FortezzaCardInfo *info;
	uint32 cardMask;
	int maxCount,found,rv;
	char **personalities;
	int *indexes;
	FortezzaPCMCIASocket *psock;
	int default_cert;


	/* hack.. only works on on-threaded systems!!!!! */
	fortezzaGlobal.fortezzaAlertArg = cx;

	switch (type) {
	case SSL_FORTEZZA_CARD_SELECT:
	    /* Don't changes cards if we are already monkeying with
	     * picking a personality...
	     */
	    if (fortezzaGlobal.state == GlobalOpen) {
		break;
	    }
	    rv = FortezzaLookupCard(&info,&cardMask,&maxCount,
						&found,NULL,NULL,PR_FALSE);
	    if (rv < 0) goto loser; /* shouldn't happen unless we trash
				      * something... */
	    fortezzaGlobal.state = GlobalOpen;
	    (void) FortezzaChooseCard(cx,info,cardMask,maxCount);
	    PORT_Free(info);
	    break;
	case SSL_FORTEZZA_CHANGE_PERSONALITY:
	case SSL_FORTEZZA_VIEW_PERSONALITY:
	    psock = fortezzaGlobal.defaultSocket;
	    if ((psock == NULL) || (psock->state == NoCard)) {
		/* FE_Alert */
	        FE_Alert(cx,XP_GetString(XP_SEC_FORTEZZA_NONE_SELECTED));
		goto loser;
	    }

	    /* Don't changes cards if we are already monkeying with
	     * picking a personality...
	     */
	    if (fortezzaGlobal.state == GlobalOpen) {
		break;
	    }

	    if (!LL_IS_ZERO(fortezzaGlobal.timeout)) {
		/* time out fortezza cards */
		int64 timeout;
		int64 now = PR_NowS();
		LL_ADD(timeout,psock->lasttime,fortezzaGlobal.timeout);
		if (LL_CMP(now, > , timeout)) {
		    psock->state = NeedPin;
		}
	    }

	    psock->lasttime = PR_NowS();

	    if (psock->state == NeedPin) {
		if (SECMOZ_GetPin(cx,psock) != SECSuccess) {
		    /* FE_Alert */
	            FE_Alert(cx,XP_GetString(XP_SEC_FORTEZZA_BAD_PIN));
		    goto loser;
		}
	        psock->state = NeedCert;
		rv = FortezzaCertInit(psock);
		if (rv < 0) {
		     /* FE_Alert */
		     FE_Alert(cx,XP_GetString(XP_SEC_FORTEZZA_PERSON_ERROR));
		     psock->state = NeedPin;
		     goto loser;
		}
	    }

	    if (type == SSL_FORTEZZA_VIEW_PERSONALITY) {
		int count = 0,i;

		for (i=0; i < psock->certificateCount; i++) {
		    if (FortezzaCertBits(psock->certFlags,i)) count++;
		}

		FortezzaShowPersonality(cx,psock->personalityList,
			psock->certificateCount,count,psock->certFlags);
		break;
	    }
	     
	    rv = FortezzaLookupPersonality(psock, &personalities, &maxCount,
								&indexes);

	    /* figure out which is our default so it can be marked selected */
	    default_cert = -1;
	    if (psock->state == Ready) {
		int i;

		for (i=0; i < maxCount; i++) {
		   if (indexes[i] == psock->template.certificate) {
			default_cert = i;
		   }
		}
	    }
		
	    if (rv < 0) {
		 goto loser;
	    }

	    if (maxCount == 0) {
		/* FE_Alert */
		goto loser;
	    }
	    fortezzaGlobal.state = GlobalOpen;
	    (void) FortezzaSelectPersonality(cx,personalities,maxCount,
								default_cert);
	    FortezzaFreePersonality(personalities);
	    break;
	     
	case SSL_FORTEZZA_CARD_INFO:
	    psock = fortezzaGlobal.defaultSocket;
	    (void) FortezzaShowCardInfo(cx,psock);
	    break;

	case SSL_FORTEZZA_LOGOUT:
	    FortezzaLogout();
	    break;
	}
loser:
    return;
}

/*
 * fortezza already has a certificate selected... use that one
 */
SECStatus
FortezzaClientAuthData(SSLSocket *ss,
			 CERTCertificate **pRetCert,
			 SECKEYPrivateKey **pRetKey)
{
    CERTCertificate *cert;
    SECKEYPrivateKey *privkey;
    FortezzaKEAContext *cv = (FortezzaKEAContext *) ss->ssl3->kea_context;

    PORT_Assert(cv != NULL);
    cert = FortezzaGetCertificate(cv->socket->socketId,
					cv->certificate,cv->socket->serial);
    if (cert == NULL) {
	return SECFailure;
    }

    privkey = FortezzaGetPrivateKey(cv);
    if (privkey == NULL) {
	CERT_DestroyCertificate(cert);
	return SECFailure;
    }
    
    *pRetCert = cert;
    *pRetKey = privkey;
    
    return(SECSuccess);
}

SECStatus
SECMOZ_FortezzaInit() {
    fortezzaGlobal.fortezzaMarkSocket = 
			(FortezzaMarkSocket) FortezzaMarkSocketWait;
    return SECSuccess;
}

/*
 * this needs to become a dialog some day
 */
#define PIN_STRING "Enter the PIN for your Fortezza Card in\nSocket %d. Note: 10 consecutive failures disables the card."
SECStatus
SECMOZ_GetPin(void *arg,void *psock)
{
    MWContext *cx;
    char *pin;
    SECStatus rv;
    char buf[200]; 
    
    cx = (MWContext *)arg;

    /* Use XP_Getstrings for internationalization */
    PR_snprintf(buf,sizeof(buf),
		PIN_STRING,((FortezzaPCMCIASocket *)psock)->socketId);
    while (1) {
    	pin = FE_PromptPassword(cx,buf);

	if (pin == 0) {
    	    return SECFailure;
	}
	rv = FortezzaPinCheck((FortezzaPCMCIASocket *)psock,pin);
	PORT_ZFree(pin,PORT_Strlen(pin));
	/* We use SECWouldBlock to indicate a soft failure (the pin did
	 * not match. Hard failures are when the card finally locks up:).
	 */
	if (rv == SECWouldBlock) {
		continue;
	}
	return rv;
    }
    return SECFailure; /* Not Reached */
}

/*
 * this one also need to become a dialog some day.
 */
SECStatus
SECMOZ_CertificateSelect(void *arg, int fd, char **names, int certCount, 
								int *cert) {
    MWContext *cx;
    SSLSocket *ss;
    
    cx = (MWContext *)arg;

    ss = ssl_FindSocket(fd);
    (void) FortezzaSelectPersonality(cx,names,certCount,-1);
    FortezzaMarkSocketWait(ss);
    fortezzaGlobal.state = GlobalOpen;

    return SECWouldBlock;
}

/*
 * and guess what... so does this one...
 */
SECStatus
SECMOZ_CardSelect(void *arg, int fd, void *ia, int cardmask,  int *psockId) {
    MWContext *cx;
    SSLSocket *ss;
    FortezzaCardInfo *info = (FortezzaCardInfo *) ia;
    
    cx = (MWContext *)arg;

    ss = ssl_FindSocket(fd);
    (void) FortezzaChooseCard(cx,info,cardmask,fortezzaGlobal.socketCount);
    FortezzaMarkSocketWait(ss);
    fortezzaGlobal.state = GlobalOpen;

    return SECWouldBlock;

}

/*
 * pop-up an alert box
 */
SECStatus
SECMOZ_FortezzaAlert(void *arg,PRBool onOpen,char *string,
						int value1,void *value2) {
    MWContext *cx;
    char *output_string;

    cx = (MWContext *)arg;


    if (onOpen) {
	output_string = PR_smprintf(string,value1,value2);
	FE_Alert(cx, output_string);
    }
    return SECSuccess;
} 

/*
 * go get a card based on it's serial number.
 */
FortezzaKEAContext *
SECMOZ_FindCardBySerial(void *wcx,unsigned char *serial) {
	int rv,i;
	uint32 cards = 0;
	int count=0;
	FortezzaPCMCIASocket *last_sock = NULL;
	FortezzaPCMCIASocket *min_sock = NULL;
	FortezzaKEAContext *cx = NULL;


	/* hack -- not thread safe... */
	fortezzaGlobal.fortezzaAlertArg = wcx;
	rv = FortezzaLookupCard( NULL,&cards,NULL,
					&count,&min_sock,&last_sock,PR_FALSE);
	if (rv < 0) return NULL;

	for (i=0; i < fortezzaGlobal.socketCount; i++) {
	    if (cards & (1<<i)) {
		FortezzaPCMCIASocket *psock = &fortezzaGlobal.sockets[i];
		if (PORT_Memcmp(serial,psock->serial,
					sizeof(CI_SERIAL_NUMBER)) == 0) {
		    /* SIGH, I'd like to to a FortezzaCardOpen here, but
		     * I may need to call SECMOZ_GetPin.. I don't have an
		     * SSL Socket get my callback from, so I have to call
		     * it directly. That's why it's here, so it doesn't
		     * pull in a bunch of User code into the server .
		     */
		    FORTEZZALOCK(psock->stateLock,psock->stateLockInit);

		    if (psock->state == NoCard) {
	    		FORTEZZAUNLOCK(psock->stateLock);
	    		return NULL;
		    }

		    
		    if (!LL_IS_ZERO(fortezzaGlobal.timeout)) {
			/* time out fortezza cards */
			int64 timeout;
			int64 now = PR_NowS();
			LL_ADD(timeout,psock->lasttime,fortezzaGlobal.timeout);
			if (LL_CMP(now, > , timeout)) {
			    psock->state = NeedPin;
			}
		    }

		    psock->lasttime = PR_NowS();

		    if (psock->state == Ready) {
			FORTEZZAUNLOCK(psock->stateLock);
			cx = FortezzaCreateKEAContext(psock);
			if (cx == NULL) return NULL;

			rv = FortezzaSelectCertificate(NULL, psock,
						       &cx->certificate);
			if (rv < 0) return NULL;
			return cx;
		    }

	    	    FORTEZZAUNLOCK(psock->stateLock); 
		    /* does *NOT* return SECWouldBlock! */
		    if (psock->state == NeedPin) {
			rv = SECMOZ_GetPin(wcx,psock);
			if (rv < 0) return NULL;
		    } else {
			rv = SECSuccess;
		    }
		    /* assumes assignment to int is atomic ! */
		    psock->state = NeedCert;
		    FORTEZZAWAKEUP(psock->stateLock);
		    rv = FortezzaCertInit(psock);
		    if (rv < 0) return NULL;

		    cx = FortezzaCreateKEAContext(psock);
		    if (cx == NULL) return NULL;

                    rv = FortezzaSelectCertificate(NULL,psock,
                                  &cx->certificate);
		    if (rv < 0) return NULL;
		    psock->state = Ready;

		    return cx;
		}
	    }
	}
	return NULL;
}