Пример #1
0
static nssCryptokiInstance *
get_cert_instance(NSSCertificate *c)
{
    nssCryptokiObject *instance, **ci;
    nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
    if (!instances) {
	return NULL;
    }
    instance = NULL;
    for (ci = instances; *ci; ci++) {
	if (!instance) {
	    instance = nssCryptokiObject_Clone(*ci);
	} else {
	    /* This only really works for two instances...  But 3.4 can't
	     * handle more anyway.  The logic is, if there are multiple
	     * instances, prefer the one that is not internal (e.g., on
	     * a hardware device.
	     */
	    if (PK11_IsInternal(instance->token->pk11slot)) {
		nssCryptokiObject_Destroy(instance);
		instance = nssCryptokiObject_Clone(*ci);
	    }
	}
    }
    nssCryptokiObjectArray_Destroy(instances);
    return instance;
}
Пример #2
0
NSSToken *
nssToken_CreateFromPK11SlotInfo(NSSTrustDomain *td, PK11SlotInfo *nss3slot)
{
    NSSToken *rvToken;
    NSSArena *arena;

    /* Don't create a token object for a disabled slot */
    if (nss3slot->disabled) {
	PORT_SetError(SEC_ERROR_NO_TOKEN);
	return NULL;
    }
    arena = nssArena_Create();
    if (!arena) {
	return NULL;
    }
    rvToken = nss_ZNEW(arena, NSSToken);
    if (!rvToken) {
	nssArena_Destroy(arena);
	return NULL;
    }
    rvToken->base.refCount = 1;
    rvToken->base.lock = PZ_NewLock(nssILockOther);
    if (!rvToken->base.lock) {
	nssArena_Destroy(arena);
	return NULL;
    }
    rvToken->base.arena = arena;
    rvToken->pk11slot = nss3slot;
    rvToken->epv = nss3slot->functionList;
    rvToken->defaultSession = nssSession_ImportNSS3Session(td->arena,
                                                       nss3slot->session,
                                                       nss3slot->sessionLock,
                                                       nss3slot->defRWSession);
    /* continue, even if rvToken->defaultSession is NULL */
    if (!PK11_IsInternal(nss3slot) && PK11_IsHW(nss3slot)) {
	rvToken->cache = nssTokenObjectCache_Create(rvToken, 
	                                            PR_TRUE, PR_TRUE, PR_TRUE);
	if (!rvToken->cache)
	    goto loser;
    }
    rvToken->trustDomain = td;
    /* Grab the token name from the PKCS#11 fixed-length buffer */
    rvToken->base.name = nssUTF8_Duplicate(nss3slot->token_name,td->arena);
    rvToken->slot = nssSlot_CreateFromPK11SlotInfo(td, nss3slot);
    if (!rvToken->slot) {
        goto loser;
    }
    rvToken->slot->token = rvToken;
    if (rvToken->defaultSession)
	rvToken->defaultSession->slot = rvToken->slot;
    return rvToken;
loser:
    PZ_DestroyLock(rvToken->base.lock);
    nssArena_Destroy(arena);
    return NULL;
}
Пример #3
0
char * 
STAN_GetCERTCertificateNameForInstance (
  PLArenaPool *arenaOpt,
  NSSCertificate *c,
  nssCryptokiInstance *instance
)
{
    NSSCryptoContext *context = c->object.cryptoContext;
    PRStatus nssrv;
    int nicklen, tokenlen, len;
    NSSUTF8 *tokenName = NULL;
    NSSUTF8 *stanNick = NULL;
    char *nickname = NULL;
    char *nick;

    if (instance) {
	stanNick = instance->label;
    } else if (context) {
	stanNick = c->object.tempName;
    }
    if (stanNick) {
	/* fill other fields needed by NSS3 functions using CERTCertificate */
	if (instance && (!PK11_IsInternal(instance->token->pk11slot) || 
	                 PORT_Strchr(stanNick, ':') != NULL) ) {
	    tokenName = nssToken_GetName(instance->token);
	    tokenlen = nssUTF8_Size(tokenName, &nssrv);
	} else {
	/* don't use token name for internal slot; 3.3 didn't */
	    tokenlen = 0;
	}
	nicklen = nssUTF8_Size(stanNick, &nssrv);
	len = tokenlen + nicklen;
	if (arenaOpt) {
	    nickname = PORT_ArenaAlloc(arenaOpt, len);
	} else {
	    nickname = PORT_Alloc(len);
	}
	nick = nickname;
	if (tokenName) {
	    memcpy(nick, tokenName, tokenlen-1);
	    nick += tokenlen-1;
	    *nick++ = ':';
	}
	memcpy(nick, stanNick, nicklen-1);
	nickname[len-1] = '\0';
    }
    return nickname;
}
Пример #4
0
nsresult
nsNSSCertificate::MarkForPermDeletion()
{
  nsNSSShutDownPreventionLock locker;
  if (isAlreadyShutDown())
    return NS_ERROR_NOT_AVAILABLE;

  // make sure user is logged in to the token
  nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();

  if (PK11_NeedLogin(mCert->slot)
      && !PK11_NeedUserInit(mCert->slot)
      && !PK11_IsInternal(mCert->slot))
  {
    if (SECSuccess != PK11_Authenticate(mCert->slot, true, ctx))
    {
      return NS_ERROR_FAILURE;
    }
  }

  mPermDelete = true;
  return NS_OK;
}
Пример #5
0
NSS_EXTERN PRStatus
STAN_ChangeCertTrust(CERTCertificate *cc, CERTCertTrust *trust)
{
    PRStatus nssrv;
    NSSCertificate *c = STAN_GetNSSCertificate(cc);
    NSSToken *tok;
    NSSTrustDomain *td;
    NSSTrust *nssTrust;
    NSSArena *arena;
    CERTCertTrust *oldTrust;
    CERTCertTrust *newTrust;
    nssListIterator *tokens;
    PRBool moving_object;
    nssCryptokiObject *newInstance;
    nssPKIObject *pkiob;

    if (c == NULL) {
        return PR_FAILURE;
    }
    oldTrust = nssTrust_GetCERTCertTrustForCert(c, cc);
    if (oldTrust) {
	if (memcmp(oldTrust, trust, sizeof (CERTCertTrust)) == 0) {
	    /* ... and the new trust is no different, done) */
	    return PR_SUCCESS;
	} else {
	    /* take over memory already allocated in cc's arena */
	    newTrust = oldTrust;
	}
    } else {
	newTrust = PORT_ArenaAlloc(cc->arena, sizeof(CERTCertTrust));
    }
    memcpy(newTrust, trust, sizeof(CERTCertTrust));
    CERT_LockCertTrust(cc);
    cc->trust = newTrust;
    CERT_UnlockCertTrust(cc);
    /* Set the NSSCerticate's trust */
    arena = nssArena_Create();
    if (!arena) return PR_FAILURE;
    nssTrust = nss_ZNEW(arena, NSSTrust);
    if (!nssTrust) {
	nssArena_Destroy(arena);
	return PR_FAILURE;
    }
    pkiob = nssPKIObject_Create(arena, NULL, cc->dbhandle, NULL, nssPKILock);
    if (!pkiob) {
	nssArena_Destroy(arena);
	return PR_FAILURE;
    }
    nssTrust->object = *pkiob;
    nssTrust->certificate = c;
    nssTrust->serverAuth = get_stan_trust(trust->sslFlags, PR_FALSE);
    nssTrust->clientAuth = get_stan_trust(trust->sslFlags, PR_TRUE);
    nssTrust->emailProtection = get_stan_trust(trust->emailFlags, PR_FALSE);
    nssTrust->codeSigning = get_stan_trust(trust->objectSigningFlags, PR_FALSE);
    nssTrust->stepUpApproved = 
                    (PRBool)(trust->sslFlags & CERTDB_GOVT_APPROVED_CA);
    if (c->object.cryptoContext != NULL) {
	/* The cert is in a context, set the trust there */
	NSSCryptoContext *cc = c->object.cryptoContext;
	nssrv = nssCryptoContext_ImportTrust(cc, nssTrust);
	if (nssrv != PR_SUCCESS) {
	    goto done;
	}
	if (c->object.numInstances == 0) {
	    /* The context is the only instance, finished */
	    goto done;
	}
    }
    td = STAN_GetDefaultTrustDomain();
    tok = stan_GetTrustToken(c);
    moving_object = PR_FALSE;
    if (tok && PK11_IsReadOnly(tok->pk11slot))  {
	NSSRWLock_LockRead(td->tokensLock);
	tokens = nssList_CreateIterator(td->tokenList);
	if (!tokens) {
	    nssrv = PR_FAILURE;
	    NSSRWLock_UnlockRead(td->tokensLock);
	    goto done;
	}
	for (tok  = (NSSToken *)nssListIterator_Start(tokens);
	     tok != (NSSToken *)NULL;
	     tok  = (NSSToken *)nssListIterator_Next(tokens))
	{
	    if (!PK11_IsReadOnly(tok->pk11slot)) break;
	}
	nssListIterator_Finish(tokens);
	nssListIterator_Destroy(tokens);
	NSSRWLock_UnlockRead(td->tokensLock);
	moving_object = PR_TRUE;
    } 
    if (tok) {
	if (moving_object) {
	    /* this is kind of hacky.  the softoken needs the cert
	     * object in order to store trust.  forcing it to be perm
	     */
	    NSSUTF8 *nickname = nssCertificate_GetNickname(c, NULL);
	    NSSASCII7 *email = NULL;

	    if (PK11_IsInternal(tok->pk11slot)) {
		email = c->email;
	    }
	    newInstance = nssToken_ImportCertificate(tok, NULL,
	                                             NSSCertificateType_PKIX,
	                                             &c->id,
	                                             nickname,
	                                             &c->encoding,
	                                             &c->issuer,
	                                             &c->subject,
	                                             &c->serial,
						     email,
	                                             PR_TRUE);
            nss_ZFreeIf(nickname);
            nickname = NULL;
	    if (!newInstance) {
		nssrv = PR_FAILURE;
		goto done;
	    }
	    nssPKIObject_AddInstance(&c->object, newInstance);
	}
	newInstance = nssToken_ImportTrust(tok, NULL, &c->encoding,
	                                   &c->issuer, &c->serial,
	                                   nssTrust->serverAuth,
	                                   nssTrust->clientAuth,
	                                   nssTrust->codeSigning,
	                                   nssTrust->emailProtection,
	                                   nssTrust->stepUpApproved, PR_TRUE);
	/* If the selected token can't handle trust, dump the trust on 
	 * the internal token */
	if (!newInstance && !PK11_IsInternalKeySlot(tok->pk11slot)) {
	    PK11SlotInfo *slot = PK11_GetInternalKeySlot();
	    NSSUTF8 *nickname = nssCertificate_GetNickname(c, NULL);
	    NSSASCII7 *email = c->email;
	    tok = PK11Slot_GetNSSToken(slot);
	    PK11_FreeSlot(slot);
	
	    newInstance = nssToken_ImportCertificate(tok, NULL,
	                                             NSSCertificateType_PKIX,
	                                             &c->id,
	                                             nickname,
	                                             &c->encoding,
	                                             &c->issuer,
	                                             &c->subject,
	                                             &c->serial,
						     email,
	                                             PR_TRUE);
            nss_ZFreeIf(nickname);
            nickname = NULL;
	    if (!newInstance) {
		nssrv = PR_FAILURE;
		goto done;
	    }
	    nssPKIObject_AddInstance(&c->object, newInstance);
	    newInstance = nssToken_ImportTrust(tok, NULL, &c->encoding,
	                                   &c->issuer, &c->serial,
	                                   nssTrust->serverAuth,
	                                   nssTrust->clientAuth,
	                                   nssTrust->codeSigning,
	                                   nssTrust->emailProtection,
	                                   nssTrust->stepUpApproved, PR_TRUE);
	}
	if (newInstance) {
	    nssCryptokiObject_Destroy(newInstance);
	    nssrv = PR_SUCCESS;
	} else {
	    nssrv = PR_FAILURE;
	}
    } else {
	nssrv = PR_FAILURE;
    }
done:
    (void)nssTrust_Destroy(nssTrust);
    return nssrv;
}
Пример #6
0
static void
fill_CERTCertificateFields(NSSCertificate *c, CERTCertificate *cc, PRBool forced)
{
    CERTCertTrust* trust = NULL;
    NSSTrust *nssTrust;
    NSSCryptoContext *context = c->object.cryptoContext;
    nssCryptokiInstance *instance;
    NSSUTF8 *stanNick = NULL;

    /* We are holding the base class object's lock on entry of this function
     * This lock protects writes to fields of the CERTCertificate .
     * It is also needed by some functions to compute values such as trust.
     */
    instance = get_cert_instance(c);

    if (instance) {
	stanNick = instance->label;
    } else if (context) {
	stanNick = c->object.tempName;
    }
    /* fill other fields needed by NSS3 functions using CERTCertificate */
    if ((!cc->nickname && stanNick) || forced) {
	PRStatus nssrv;
	int nicklen, tokenlen, len;
	NSSUTF8 *tokenName = NULL;
	char *nick;
	if (instance && 
	     (!PK11_IsInternal(instance->token->pk11slot) || 
	      (stanNick && PORT_Strchr(stanNick, ':') != NULL))) {
	    tokenName = nssToken_GetName(instance->token);
	    tokenlen = nssUTF8_Size(tokenName, &nssrv);
	} else {
	    /* don't use token name for internal slot; 3.3 didn't */
	    tokenlen = 0;
	}
	if (stanNick) {
	    nicklen = nssUTF8_Size(stanNick, &nssrv);
	    len = tokenlen + nicklen;
	    nick = PORT_ArenaAlloc(cc->arena, len);
	    if (tokenName) {
		memcpy(nick, tokenName, tokenlen-1);
		nick[tokenlen-1] = ':';
		memcpy(nick+tokenlen, stanNick, nicklen-1);
	    } else {
		memcpy(nick, stanNick, nicklen-1);
	    }
	    nick[len-1] = '\0';
            cc->nickname = nick;
	} else {
	    cc->nickname = NULL;
	}
    }
    if (context) {
	/* trust */
	nssTrust = nssCryptoContext_FindTrustForCertificate(context, c);
	if (nssTrust) {
            trust = cert_trust_from_stan_trust(nssTrust, cc->arena);
            if (trust) {
                /* we should destroy cc->trust before replacing it, but it's
                   allocated in cc->arena, so memory growth will occur on each
                   refresh */
                cc->trust = trust;
            }
	    nssTrust_Destroy(nssTrust);
	}
    } else if (instance) {
	/* slot */
	if (cc->slot != instance->token->pk11slot) {
	    if (cc->slot) {
		PK11_FreeSlot(cc->slot);
	    }
	    cc->slot = PK11_ReferenceSlot(instance->token->pk11slot);
	}
	cc->ownSlot = PR_TRUE;
	/* pkcs11ID */
	cc->pkcs11ID = instance->handle;
	/* trust */
	trust = nssTrust_GetCERTCertTrustForCert(c, cc);
        if (trust) {
            /* we should destroy cc->trust before replacing it, but it's
               allocated in cc->arena, so memory growth will occur on each
               refresh */
            cc->trust = trust;
        }
	nssCryptokiObject_Destroy(instance);
    } 
    /* database handle is now the trust domain */
    cc->dbhandle = c->object.trustDomain;
    /* subjectList ? */
    /* istemp and isperm are supported in NSS 3.4 */
    cc->istemp = PR_FALSE; /* CERT_NewTemp will override this */
    cc->isperm = PR_TRUE;  /* by default */
    /* pointer back */
    cc->nssCertificate = c;
    if (trust) {
	/* force the cert type to be recomputed to include trust info */
	PRUint32 nsCertType = cert_ComputeCertType(cc);

	/* Assert that it is safe to cast &cc->nsCertType to "PRInt32 *" */
	PORT_Assert(sizeof(cc->nsCertType) == sizeof(PRInt32));
	PR_AtomicSet((PRInt32 *)&cc->nsCertType, nsCertType);
    }
}
Пример #7
0
/*
 * generate an RSA signature key
 *
 * e is fixed at 3, without discussion.  That would not be wise if these
 * keys were to be used for encryption, but for signatures there are some
 * real speed advantages.
 * See also: https://www.imperialviolet.org/2012/03/16/rsae.html
 */
void rsasigkey(int nbits, int seedbits, char *configdir, char *password)
{
	SECStatus rv;
	PK11RSAGenParams rsaparams = { nbits, (long) E };
	secuPWData pwdata = { PW_NONE, NULL };
	PK11SlotInfo *slot = NULL;
	SECKEYPrivateKey *privkey = NULL;
	SECKEYPublicKey *pubkey = NULL;
	realtime_t now = realnow();

	if (password == NULL) {
		pwdata.source = PW_NONE;
	} else {
		/* check if passwd == configdir/nsspassword */
		size_t cdl = strlen(configdir);
		size_t pwl = strlen(password);
		static const char suf[] = "/nsspassword";

		if (pwl == cdl + sizeof(suf) - 1 &&
			memeq(password, configdir, cdl) &&
			memeq(password + cdl, suf, sizeof(suf)))
			pwdata.source = PW_FROMFILE;
		else
			pwdata.source = PW_PLAINTEXT;
	}
	pwdata.data = password;

	lsw_nss_buf_t err;
	if (!lsw_nss_setup(configdir, FALSE/*rw*/, GetModulePassword, err)) {
		fprintf(stderr, "%s: %s\n", me, err);
		exit(1);
	}

#ifdef FIPS_CHECK
	if (PK11_IsFIPS() && !FIPSCHECK_verify(NULL, NULL)) {
		fprintf(stderr,
			"FIPS HMAC integrity verification test failed.\n");
		exit(1);
	}
#endif

	if (PK11_IsFIPS() && password == NULL) {
		fprintf(stderr,
			"%s: On FIPS mode a password is required\n",
			me);
		exit(1);
	}

	/* Good for now but someone may want to use a hardware token */
	slot = PK11_GetInternalKeySlot();
	/* In which case this may be better */
	/* slot = PK11_GetBestSlot(CKM_RSA_PKCS_KEY_PAIR_GEN, password ? &pwdata : NULL); */
	/* or the user may specify the name of a token. */

#if 0
	if (PK11_IsFIPS() || !PK11_IsInternal(slot)) {
		rv = PK11_Authenticate(slot, PR_FALSE, &pwdata);
		if (rv != SECSuccess) {
			fprintf(stderr, "%s: could not authenticate to token '%s'\n",
				me, PK11_GetTokenName(slot));
			return;
		}
	}
#endif /* 0 */

	/* Do some random-number initialization. */
	UpdateNSS_RNG(seedbits);
	/* Log in to the token */
	if (password != NULL) {
		rv = PK11_Authenticate(slot, PR_FALSE, &pwdata);
		if (rv != SECSuccess) {
			fprintf(stderr,
				"%s: could not authenticate to token '%s'\n",
				me, PK11_GetTokenName(slot));
			return;
		}
	}
	privkey = PK11_GenerateKeyPair(slot,
				       CKM_RSA_PKCS_KEY_PAIR_GEN,
				       &rsaparams, &pubkey,
				       PR_TRUE,
				       password != NULL? PR_TRUE : PR_FALSE,
				       &pwdata);
	/* inTheToken, isSensitive, passwordCallbackFunction */
	if (privkey == NULL) {
		fprintf(stderr,
			"%s: key pair generation failed: \"%d\"\n", me,
			PORT_GetError());
		return;
	}

	chunk_t public_modulus = {
		.ptr = pubkey->u.rsa.modulus.data,
		.len = pubkey->u.rsa.modulus.len,
	};
	chunk_t public_exponent = {
		.ptr = pubkey->u.rsa.publicExponent.data,
		.len = pubkey->u.rsa.publicExponent.len,
	};

	char *hex_ckaid;
	{
		SECItem *ckaid = PK11_GetLowLevelKeyIDForPrivateKey(privkey);
		if (ckaid == NULL) {
			fprintf(stderr, "%s: 'CKAID' calculation failed\n", me);
			exit(1);
		}
		hex_ckaid = strdup(conv(ckaid->data, ckaid->len, 16));
		SECITEM_FreeItem(ckaid, PR_TRUE);
	}

	/*privkey->wincx = &pwdata;*/
	PORT_Assert(pubkey != NULL);
	fprintf(stderr, "Generated RSA key pair with CKAID %s was stored in the NSS database\n",
		hex_ckaid);

	/* and the output */
	report("output...\n");  /* deliberate extra newline */
	printf("\t# RSA %d bits   %s   %s", nbits, outputhostname,
		ctime(&now.real_secs));
	/* ctime provides \n */
	printf("\t# for signatures only, UNSAFE FOR ENCRYPTION\n");

	printf("\t#ckaid=%s\n", hex_ckaid);

	/* RFC2537/RFC3110-ish format */
	{
		char *bundle = base64_bundle(E, public_modulus);
		printf("\t#pubkey=%s\n", bundle);
		pfree(bundle);
	}

	printf("\tModulus: 0x%s\n", conv(public_modulus.ptr, public_modulus.len, 16));
	printf("\tPublicExponent: 0x%s\n", conv(public_exponent.ptr, public_exponent.len, 16));

	if (hex_ckaid != NULL)
		free(hex_ckaid);
	if (privkey != NULL)
		SECKEY_DestroyPrivateKey(privkey);
	if (pubkey != NULL)
		SECKEY_DestroyPublicKey(pubkey);

	lsw_nss_shutdown(LSW_NSS_CLEANUP);
}

/*
 * getrandom - get some random bytes from /dev/random (or wherever)
 * NOTE: This is only used for additional seeding of the NSS RNG
 */
void getrandom(size_t nbytes, unsigned char *buf)
{
	size_t ndone;
	int dev;
	ssize_t got;

	dev = open(device, 0);
	if (dev < 0) {
		fprintf(stderr, "%s: could not open %s (%s)\n", me,
			device, strerror(errno));
		exit(1);
	}

	ndone = 0;
	if (verbose) {
		fprintf(stderr, "getting %d random seed bytes for NSS from %s...\n",
			(int) nbytes * BITS_PER_BYTE,
			device);
	}
	while (ndone < nbytes) {
		got = read(dev, buf + ndone, nbytes - ndone);
		if (got < 0) {
			fprintf(stderr, "%s: read error on %s (%s)\n", me,
				device, strerror(errno));
			exit(1);
		}
		if (got == 0) {
			fprintf(stderr, "%s: eof on %s!?!\n", me, device);
			exit(1);
		}
		ndone += got;
	}

	close(dev);
}

/*
   - conv - convert bits to output in specified datatot format
 * NOTE: result points into a STATIC buffer
 */
static const char *conv(const unsigned char *bits, size_t nbytes, int format)
{
	static char convbuf[MAXBITS / 4 + 50];  /* enough for hex */
	size_t n;

	n = datatot(bits, nbytes, format, convbuf, sizeof(convbuf));
	if (n == 0) {
		fprintf(stderr, "%s: can't-happen convert error\n", me);
		exit(1);
	}
	if (n > sizeof(convbuf)) {
		fprintf(stderr,
			"%s: can't-happen convert overflow (need %d)\n",
			me, (int) n);
		exit(1);
	}
	return convbuf;
}

/*
   - report - report progress, if indicated
 */
void report(msg)
char *msg;
{
	if (!verbose)
		return;

	fprintf(stderr, "%s\n", msg);
}
Пример #8
0
// nsPKCS12Blob::ExportToFile
//
// Having already loaded the certs, form them into a blob (loading the keys
// also), encode the blob, and stuff it into the file.
//
// TODO: handle slots correctly
//       mirror "slotToUse" behavior from PSM 1.x
//       verify the cert array to start off with?
//       open output file as nsIFileStream object?
//       set appropriate error codes
nsresult
nsPKCS12Blob::ExportToFile(nsILocalFile *file, 
                           nsIX509Cert **certs, int numCerts)
{
  nsNSSShutDownPreventionLock locker;
  nsresult rv;
  SECStatus srv = SECSuccess;
  SEC_PKCS12ExportContext *ecx = NULL;
  SEC_PKCS12SafeInfo *certSafe = NULL, *keySafe = NULL;
  SECItem unicodePw;
  nsAutoString filePath;
  int i;
  nsCOMPtr<nsILocalFile> localFileRef;
  NS_ASSERTION(mToken, "Need to set the token before exporting");
  // init slot

  bool InformedUserNoSmartcardBackup = false;
  int numCertsExported = 0;

  rv = mToken->Login(true);
  if (NS_FAILED(rv)) goto finish;
  // get file password (unicode)
  unicodePw.data = NULL;
  rv = newPKCS12FilePassword(&unicodePw);
  if (NS_FAILED(rv)) goto finish;
  if (unicodePw.data == NULL) {
    handleError(PIP_PKCS12_USER_CANCELED);
    return NS_OK;
  }
  // what about slotToUse in psm 1.x ???
  // create export context
  ecx = SEC_PKCS12CreateExportContext(NULL, NULL, NULL /*slot*/, NULL);
  if (!ecx) {
    srv = SECFailure;
    goto finish;
  }
  // add password integrity
  srv = SEC_PKCS12AddPasswordIntegrity(ecx, &unicodePw, SEC_OID_SHA1);
  if (srv) goto finish;
#if 0
  // count the number of certs to export
  nrv = mCertArray->Count(&numCerts);
  if (NS_FAILED(nrv)) goto finish;
  // loop over the certs
  for (i=0; i<numCerts; i++) {
    nsCOMPtr<nsIX509Cert> cert;
    nrv = mCertArray->GetElementAt(i, getter_AddRefs(cert));
    if (NS_FAILED(nrv)) goto finish;
#endif
  for (i=0; i<numCerts; i++) {
//    nsNSSCertificate *cert = reinterpret_cast<nsNSSCertificate *>(certs[i]);
    nsNSSCertificate *cert = (nsNSSCertificate *)certs[i];
    // get it as a CERTCertificate XXX
    CERTCertificate *nssCert = NULL;
    CERTCertificateCleaner nssCertCleaner(nssCert);
    nssCert = cert->GetCert();
    if (!nssCert) {
      rv = NS_ERROR_FAILURE;
      goto finish;
    }
    // We can only successfully export certs that are on 
    // internal token.  Most, if not all, smart card vendors
    // won't let you extract the private key (in any way
    // shape or form) from the card.  So let's punt if 
    // the cert is not in the internal db.
    if (nssCert->slot && !PK11_IsInternal(nssCert->slot)) {
      // we aren't the internal token, see if the key is extractable.
      SECKEYPrivateKey *privKey=PK11_FindKeyByDERCert(nssCert->slot,
                                                      nssCert, this);

      if (privKey) {
        bool privKeyIsExtractable = isExtractable(privKey);

        SECKEY_DestroyPrivateKey(privKey);

        if (!privKeyIsExtractable) {
          if (!InformedUserNoSmartcardBackup) {
            InformedUserNoSmartcardBackup = true;
            handleError(PIP_PKCS12_NOSMARTCARD_EXPORT);
          }
          continue;
        }
      }
    }

    // XXX this is why, to verify the slot is the same
    // PK11_FindObjectForCert(nssCert, NULL, slot);
    // create the cert and key safes
    keySafe = SEC_PKCS12CreateUnencryptedSafe(ecx);
    if (!SEC_PKCS12IsEncryptionAllowed() || PK11_IsFIPS()) {
      certSafe = keySafe;
    } else {
      certSafe = SEC_PKCS12CreatePasswordPrivSafe(ecx, &unicodePw,
                           SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC);
    }
    if (!certSafe || !keySafe) {
      rv = NS_ERROR_FAILURE;
      goto finish;
    }
    // add the cert and key to the blob
    srv = SEC_PKCS12AddCertAndKey(ecx, certSafe, NULL, nssCert,
                                  CERT_GetDefaultCertDB(), // XXX
                                  keySafe, NULL, true, &unicodePw,
                      SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC);
    if (srv) goto finish;
    // cert was dup'ed, so release it
    ++numCertsExported;
  }
  
  if (!numCertsExported) goto finish;
  
  // prepare the instance to write to an export file
  this->mTmpFile = NULL;
  file->GetPath(filePath);
  // Use the nsCOMPtr var localFileRef so that
  // the reference to the nsILocalFile we create gets released as soon as
  // we're out of scope, ie when this function exits.
  if (filePath.RFind(".p12", true, -1, 4) < 0) {
    // We're going to add the .p12 extension to the file name just like
    // Communicator used to.  We create a new nsILocalFile and initialize
    // it with the new patch.
    filePath.AppendLiteral(".p12");
    localFileRef = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
    if (NS_FAILED(rv)) goto finish;
    localFileRef->InitWithPath(filePath);
    file = localFileRef;
  }
  rv = file->OpenNSPRFileDesc(PR_RDWR|PR_CREATE_FILE|PR_TRUNCATE, 0664, 
                              &mTmpFile);
  if (NS_FAILED(rv) || !this->mTmpFile) goto finish;
  // encode and write
  srv = SEC_PKCS12Encode(ecx, write_export_file, this);
  if (srv) goto finish;
  handleError(PIP_PKCS12_BACKUP_OK);
finish:
  if (NS_FAILED(rv) || srv != SECSuccess) {
    handleError(PIP_PKCS12_BACKUP_FAILED);
  }
  if (ecx)
    SEC_PKCS12DestroyExportContext(ecx);
  if (this->mTmpFile) {
    PR_Close(this->mTmpFile);
    this->mTmpFile = NULL;
  }
  SECITEM_ZfreeItem(&unicodePw, false);
  return rv;
}

///////////////////////////////////////////////////////////////////////
//
//  private members
//
///////////////////////////////////////////////////////////////////////

// unicodeToItem
//
// For the NSS PKCS#12 library, must convert PRUnichars (shorts) to
// a buffer of octets.  Must handle byte order correctly.
// TODO: Is there a mozilla way to do this?  In the string lib?
void
nsPKCS12Blob::unicodeToItem(const PRUnichar *uni, SECItem *item)
{
  int len = 0;
  while (uni[len++] != 0);
  SECITEM_AllocItem(NULL, item, sizeof(PRUnichar) * len);
#ifdef IS_LITTLE_ENDIAN
  int i = 0;
  for (i=0; i<len; i++) {
    item->data[2*i  ] = (unsigned char )(uni[i] << 8);
    item->data[2*i+1] = (unsigned char )(uni[i]);
  }
#else
  memcpy(item->data, uni, item->len);
#endif
}
Пример #9
0
SECStatus
PK11_ImportAndReturnPrivateKey(PK11SlotInfo *slot, SECKEYRawPrivateKey *lpk, 
	SECItem *nickname, SECItem *publicValue, PRBool isPerm, 
	PRBool isPrivate, unsigned int keyUsage, SECKEYPrivateKey **privk,
	void *wincx) 
{
    CK_BBOOL cktrue = CK_TRUE;
    CK_BBOOL ckfalse = CK_FALSE;
    CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
    CK_KEY_TYPE keyType = CKK_RSA;
    CK_OBJECT_HANDLE objectID;
    CK_ATTRIBUTE theTemplate[20];
    int templateCount = 0;
    SECStatus rv = SECFailure;
    PRArenaPool *arena;
    CK_ATTRIBUTE *attrs;
    CK_ATTRIBUTE *signedattr = NULL;
    int signedcount = 0;
    CK_ATTRIBUTE *ap;
    SECItem *ck_id = NULL;

    arena = PORT_NewArena(2048);
    if(!arena) {
	return SECFailure;
    }

    attrs = theTemplate;


    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++;
    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++;
    PK11_SETATTRS(attrs, CKA_TOKEN, isPerm ? &cktrue : &ckfalse, 
						sizeof(CK_BBOOL) ); attrs++;
    PK11_SETATTRS(attrs, CKA_SENSITIVE, isPrivate ? &cktrue : &ckfalse, 
						sizeof(CK_BBOOL) ); attrs++;
    PK11_SETATTRS(attrs, CKA_PRIVATE, isPrivate ? &cktrue : &ckfalse,
						 sizeof(CK_BBOOL) ); attrs++;

    switch (lpk->keyType) {
    case rsaKey:
	    keyType = CKK_RSA;
	    PK11_SETATTRS(attrs, CKA_UNWRAP, (keyUsage & KU_KEY_ENCIPHERMENT) ?
				&cktrue : &ckfalse, sizeof(CK_BBOOL) ); attrs++;
	    PK11_SETATTRS(attrs, CKA_DECRYPT, (keyUsage & KU_DATA_ENCIPHERMENT) ?
				&cktrue : &ckfalse, sizeof(CK_BBOOL) ); attrs++;
	    PK11_SETATTRS(attrs, CKA_SIGN, (keyUsage & KU_DIGITAL_SIGNATURE) ? 
				&cktrue : &ckfalse, sizeof(CK_BBOOL) ); attrs++;
	    PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, 
				(keyUsage & KU_DIGITAL_SIGNATURE) ? 
				&cktrue : &ckfalse, sizeof(CK_BBOOL) ); attrs++;
	    ck_id = PK11_MakeIDFromPubKey(&lpk->u.rsa.modulus);
	    if (ck_id == NULL) {
		goto loser;
	    }
	    PK11_SETATTRS(attrs, CKA_ID, ck_id->data,ck_id->len); attrs++;
	    if (nickname) {
		PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len); attrs++; 
	    } 
	    signedattr = attrs;
	    PK11_SETATTRS(attrs, CKA_MODULUS, lpk->u.rsa.modulus.data,
						lpk->u.rsa.modulus.len); attrs++;
	    PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, 
	     			lpk->u.rsa.publicExponent.data,
				lpk->u.rsa.publicExponent.len); attrs++;
	    PK11_SETATTRS(attrs, CKA_PRIVATE_EXPONENT, 
	     			lpk->u.rsa.privateExponent.data,
				lpk->u.rsa.privateExponent.len); attrs++;
	    PK11_SETATTRS(attrs, CKA_PRIME_1, 
	     			lpk->u.rsa.prime1.data,
				lpk->u.rsa.prime1.len); attrs++;
	    PK11_SETATTRS(attrs, CKA_PRIME_2, 
	     			lpk->u.rsa.prime2.data,
				lpk->u.rsa.prime2.len); attrs++;
	    PK11_SETATTRS(attrs, CKA_EXPONENT_1, 
	     			lpk->u.rsa.exponent1.data,
				lpk->u.rsa.exponent1.len); attrs++;
	    PK11_SETATTRS(attrs, CKA_EXPONENT_2, 
	     			lpk->u.rsa.exponent2.data,
				lpk->u.rsa.exponent2.len); attrs++;
	    PK11_SETATTRS(attrs, CKA_COEFFICIENT, 
	     			lpk->u.rsa.coefficient.data,
				lpk->u.rsa.coefficient.len); attrs++;
	    break;
    case dsaKey:
	    keyType = CKK_DSA;
	    /* To make our intenal PKCS #11 module work correctly with 
	     * our database, we need to pass in the public key value for 
	     * this dsa key. We have a netscape only CKA_ value to do this.
	     * Only send it to internal slots */
	    if( publicValue == NULL ) {
		goto loser;
	    }
	    if (PK11_IsInternal(slot)) {
	        PK11_SETATTRS(attrs, CKA_NETSCAPE_DB,
				publicValue->data, publicValue->len); attrs++;
	    }
	    PK11_SETATTRS(attrs, CKA_SIGN, &cktrue, sizeof(CK_BBOOL)); attrs++;
	    PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, &cktrue, sizeof(CK_BBOOL)); attrs++;
	    if(nickname) {
		PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
		attrs++; 
	    } 
	    ck_id = PK11_MakeIDFromPubKey(publicValue);
	    if (ck_id == NULL) {
		goto loser;
	    }
	    PK11_SETATTRS(attrs, CKA_ID, ck_id->data,ck_id->len); attrs++;
	    signedattr = attrs;
	    PK11_SETATTRS(attrs, CKA_PRIME,    lpk->u.dsa.params.prime.data,
				lpk->u.dsa.params.prime.len); attrs++;
	    PK11_SETATTRS(attrs,CKA_SUBPRIME,lpk->u.dsa.params.subPrime.data,
				lpk->u.dsa.params.subPrime.len); attrs++;
	    PK11_SETATTRS(attrs, CKA_BASE,  lpk->u.dsa.params.base.data,
					lpk->u.dsa.params.base.len); attrs++;
	    PK11_SETATTRS(attrs, CKA_VALUE,    lpk->u.dsa.privateValue.data, 
					lpk->u.dsa.privateValue.len); attrs++;
	    break;
     case dhKey:
	    keyType = CKK_DH;
	    /* To make our intenal PKCS #11 module work correctly with 
	     * our database, we need to pass in the public key value for 
	     * this dh key. We have a netscape only CKA_ value to do this.
	     * Only send it to internal slots */
	    if (PK11_IsInternal(slot)) {
	        PK11_SETATTRS(attrs, CKA_NETSCAPE_DB,
				publicValue->data, publicValue->len); attrs++;
	    }
	    PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL)); attrs++;
	    if(nickname) {
		PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
		attrs++; 
	    } 
	    ck_id = PK11_MakeIDFromPubKey(publicValue);
	    if (ck_id == NULL) {
		goto loser;
	    }
	    PK11_SETATTRS(attrs, CKA_ID, ck_id->data,ck_id->len); attrs++;
	    signedattr = attrs;
	    PK11_SETATTRS(attrs, CKA_PRIME,    lpk->u.dh.prime.data,
				lpk->u.dh.prime.len); attrs++;
	    PK11_SETATTRS(attrs, CKA_BASE,  lpk->u.dh.base.data,
					lpk->u.dh.base.len); attrs++;
	    PK11_SETATTRS(attrs, CKA_VALUE,    lpk->u.dh.privateValue.data, 
					lpk->u.dh.privateValue.len); attrs++;
	    break;
	/* what about fortezza??? */
    default:
	    PORT_SetError(SEC_ERROR_BAD_KEY);
	    goto loser;
    }
    templateCount = attrs - theTemplate;
    PORT_Assert(templateCount <= sizeof(theTemplate)/sizeof(CK_ATTRIBUTE));
    PORT_Assert(signedattr != NULL);
    signedcount = attrs - signedattr;

    for (ap=signedattr; signedcount; ap++, signedcount--) {
	pk11_SignedToUnsigned(ap);
    }

    rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION,
			theTemplate, templateCount, isPerm, &objectID);

    /* create and return a SECKEYPrivateKey */
    if( rv == SECSuccess && privk != NULL) {
	*privk = PK11_MakePrivKey(slot, lpk->keyType, !isPerm, objectID, wincx);
	if( *privk == NULL ) {
	    rv = SECFailure;
	}
    }
loser:
    if (ck_id) {
	SECITEM_ZfreeItem(ck_id, PR_TRUE);
    }
    return rv;
}
Пример #10
0
void
nsNSSCertificateDB::get_default_nickname(CERTCertificate *cert, 
                                         nsIInterfaceRequestor* ctx,
                                         nsCString &nickname)
{
  nickname.Truncate();

  nsNSSShutDownPreventionLock locker;
  nsresult rv;
  CK_OBJECT_HANDLE keyHandle;

  CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  if (NS_FAILED(rv))
    return;

  nsCAutoString username;
  char *temp_un = CERT_GetCommonName(&cert->subject);
  if (temp_un) {
    username = temp_un;
    PORT_Free(temp_un);
    temp_un = nsnull;
  }

  nsCAutoString caname;
  char *temp_ca = CERT_GetOrgName(&cert->issuer);
  if (temp_ca) {
    caname = temp_ca;
    PORT_Free(temp_ca);
    temp_ca = nsnull;
  }

  nsAutoString tmpNickFmt;
  nssComponent->GetPIPNSSBundleString("nick_template", tmpNickFmt);
  NS_ConvertUTF16toUTF8 nickFmt(tmpNickFmt);

  nsCAutoString baseName;
  char *temp_nn = PR_smprintf(nickFmt.get(), username.get(), caname.get());
  if (!temp_nn) {
    return;
  } else {
    baseName = temp_nn;
    PR_smprintf_free(temp_nn);
    temp_nn = nsnull;
  }

  nickname = baseName;

  /*
   * We need to see if the private key exists on a token, if it does
   * then we need to check for nicknames that already exist on the smart
   * card.
   */
  PK11SlotInfo *slot = PK11_KeyForCertExists(cert, &keyHandle, ctx);
  PK11SlotInfoCleaner slotCleaner(slot);
  if (!slot)
    return;

  if (!PK11_IsInternal(slot)) {
    char *tmp = PR_smprintf("%s:%s", PK11_GetTokenName(slot), baseName.get());
    if (!tmp) {
      nickname.Truncate();
      return;
    }
    baseName = tmp;
    PR_smprintf_free(tmp);

    nickname = baseName;
  }

  int count = 1;
  while (true) {
    if ( count > 1 ) {
      char *tmp = PR_smprintf("%s #%d", baseName.get(), count);
      if (!tmp) {
        nickname.Truncate();
        return;
      }
      nickname = tmp;
      PR_smprintf_free(tmp);
    }

    CERTCertificate *dummycert = nsnull;
    CERTCertificateCleaner dummycertCleaner(dummycert);

    if (PK11_IsInternal(slot)) {
      /* look up the nickname to make sure it isn't in use already */
      dummycert = CERT_FindCertByNickname(defaultcertdb, nickname.get());

    } else {
      /*
       * Check the cert against others that already live on the smart 
       * card.
       */
      dummycert = PK11_FindCertFromNickname(nickname.get(), ctx);
      if (dummycert != NULL) {
	/*
	 * Make sure the subject names are different.
	 */ 
	if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual)
	{
	  /*
	   * There is another certificate with the same nickname and
	   * the same subject name on the smart card, so let's use this
	   * nickname.
	   */
	  CERT_DestroyCertificate(dummycert);
	  dummycert = NULL;
	}
      }
    }
    if (!dummycert) 
      break;
    
    count++;
  }
}
Пример #11
0
static char *
getPin(SVRCOREPinObj *ctx, const char *tokenName, PRBool retry)
{
  SVRCOREFilePinObj *obj = (SVRCOREFilePinObj*)ctx;
  PK11SlotInfo *slot;
  int is_internal_token = 0;
  FILE *pinfile = 0;
  char *res = 0;

  /* In really bad situations, where we cannot allocate memory
   * for a bad PIN list, the entire PIN object is disabled.
   */
  if (obj->disabled) return 0;

  /*
   * If the application is retrying the PIN, the one in the file is
   * probably wrong.  It's important that we avoid returning this
   * PIN to the caller each time, since that will result in disabling
   * the token. 
   */
  {
    Node *p;

    for(p = obj->badPinList;p;p = p->next)
      if (strcmp(p->tokenName, tokenName) == 0) break;

    if (p) return 0;
  }

  /* Mark it as bad (in the hash table) so that we remember
   * to never return it again.
   */
  if (retry)
  {
    Node *ent = 0;

    do {
      ent = (Node *)malloc(sizeof (Node));
      if (!ent) break;

      ent->tokenName = strdup(tokenName);

      if (!ent->tokenName)
      {
        free(ent);
        ent = 0;
      }
    } while(0);

    /* If adding fails, disable the whole object */
    if (!ent) {
        obj->disabled = PR_TRUE;
    }

    if (ent) {
        /* Add to list */
        ent->next = obj->badPinList;
        obj->badPinList = ent;
    }

    return 0;
  }

  slot = PK11_FindSlotByName((char *)tokenName);
  if (slot) {
      is_internal_token = PK11_IsInternal(slot);
      PK11_FreeSlot(slot);
  }

  do {
    char line[128];

    pinfile = fopen(obj->filename, "rt");
    if (!pinfile) break; 

    /* Read lines from the file */
    while(fgets(line, sizeof line, pinfile))
    {
      char *pin;
      char *delim;

      /* Find the ":" */
      delim = strchr(line, ':');
      if (!delim) continue;

      /* Terminate name field and skip ";" */
      *delim++ = 0;

      if (strcmp(line, tokenName) == 0 ||
	  (is_internal_token &&
	      (strcmp(line, "Communicator Certificate DB") == 0 ||
	       strcmp(line, "Internal (Software) Token") == 0)))
      {
        pin = delim;
        delim = strchr(pin, '\n');
        if (delim) *delim = 0;

        res = strdup(pin);
        break;
      }
    }

    /* Clear any sensitive data */
    memset(line, 0, sizeof line);
  } while(0);

  if (pinfile) fclose(pinfile);

  return res;
}
Пример #12
0
/*
 * generate an RSA signature key
 *
 * e is fixed at 3, without discussion.  That would not be wise if these
 * keys were to be used for encryption, but for signatures there are some
 * real speed advantages.
 * See also: https://www.imperialviolet.org/2012/03/16/rsae.html
 */
void rsasigkey(int nbits, char *configdir, char *password)
{
	SECStatus rv;
	PK11RSAGenParams rsaparams      = { nbits, (long) E };
	secuPWData pwdata              = { PW_NONE, NULL };
	PK11SlotInfo *slot              = NULL;
	SECKEYPrivateKey *privkey       = NULL;
	SECKEYPublicKey *pubkey         = NULL;
	unsigned char *bundp            = NULL;
	mpz_t n;
	mpz_t e;
	size_t bs;
	char n_str[3 + MAXBITS / 4 + 1];
	realtime_t now = realnow();

	mpz_init(n);
	mpz_init(e);

	if (password == NULL) {
		pwdata.source = PW_NONE;
	} else {
		/* check if passwd == configdir/nsspassword */
		size_t cdl = strlen(configdir);
		size_t pwl = strlen(password);
		static const char suf[] = "/nsspassword";

		if (pwl == cdl + sizeof(suf) - 1 &&
			memeq(password, configdir, cdl) &&
			memeq(password + cdl, suf, sizeof(suf)))
			pwdata.source = PW_FROMFILE;
		else
			pwdata.source = PW_PLAINTEXT;
	}
	pwdata.data = password;

	PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 1);

	rv = NSS_InitReadWrite(configdir);
	if (rv != SECSuccess) {
		fprintf(stderr, "%s: NSS_InitReadWrite(%s) returned %d\n",
			me, configdir, PR_GetError());
		exit(1);
	}
#ifdef FIPS_CHECK
	if (PK11_IsFIPS() && !FIPSCHECK_verify(NULL, NULL)) {
		fprintf(stderr,
			"FIPS HMAC integrity verification test failed.\n");
		exit(1);
	}
#endif

	if (PK11_IsFIPS() && !password) {
		fprintf(stderr,
			"%s: On FIPS mode a password is required\n",
			me);
		exit(1);
	}

	PK11_SetPasswordFunc(GetModulePassword);

	/* Good for now but someone may want to use a hardware token */
	slot = PK11_GetInternalKeySlot();
	/* In which case this may be better */
	/* slot = PK11_GetBestSlot(CKM_RSA_PKCS_KEY_PAIR_GEN, password ? &pwdata : NULL); */
	/* or the user may specify the name of a token. */

#if 0
	if (PK11_IsFIPS() || !PK11_IsInternal(slot)) {
		rv = PK11_Authenticate(slot, PR_FALSE, &pwdata);
		if (rv != SECSuccess) {
			fprintf(stderr, "%s: could not authenticate to token '%s'\n",
				me, PK11_GetTokenName(slot));
			return;
		}
	}
#endif /* 0 */

	/* Do some random-number initialization. */
	UpdateNSS_RNG();
	/* Log in to the token */
	if (password) {
		rv = PK11_Authenticate(slot, PR_FALSE, &pwdata);
		if (rv != SECSuccess) {
			fprintf(stderr,
				"%s: could not authenticate to token '%s'\n",
				me, PK11_GetTokenName(slot));
			return;
		}
	}
	privkey = PK11_GenerateKeyPair(slot,
				       CKM_RSA_PKCS_KEY_PAIR_GEN,
				       &rsaparams, &pubkey,
				       PR_TRUE,
				       password ? PR_TRUE : PR_FALSE,
				       &pwdata);
	/* inTheToken, isSensitive, passwordCallbackFunction */
	if (!privkey) {
		fprintf(stderr,
			"%s: key pair generation failed: \"%d\"\n", me,
			PORT_GetError());
		return;
	}

	/*privkey->wincx = &pwdata;*/
	PORT_Assert(pubkey != NULL);
	fprintf(stderr,
		"Generated RSA key pair using the NSS database\n");

	SECItemToHex(getModulus(pubkey), n_str);
	assert(!mpz_set_str(n, n_str, 16));

	/* and the output */
	report("output...\n");  /* deliberate extra newline */
	printf("\t# RSA %d bits   %s   %s", nbits, outputhostname,
		ctime(&now.real_secs));
	/* ctime provides \n */
	printf("\t# for signatures only, UNSAFE FOR ENCRYPTION\n");
	bundp = bundle(E, n, &bs);
	printf("\t#pubkey=%s\n", conv(bundp, bs, 's')); /* RFC2537ish format */
	printf("\tModulus: %s\n", hexOut(getModulus(pubkey)));
	printf("\tPublicExponent: %s\n",
	       hexOut(getPublicExponent(pubkey)));

	SECItem *ckaID = PK11_MakeIDFromPubKey(getModulus(pubkey));
	if (ckaID != NULL) {
		printf("\t# everything after this point is CKA_ID in hex format - not the real values \n");
		printf("\tPrivateExponent: %s\n", hexOut(ckaID));
		printf("\tPrime1: %s\n", hexOut(ckaID));
		printf("\tPrime2: %s\n", hexOut(ckaID));
		printf("\tExponent1: %s\n", hexOut(ckaID));
		printf("\tExponent2: %s\n", hexOut(ckaID));
		printf("\tCoefficient: %s\n", hexOut(ckaID));
		printf("\tCKAIDNSS: %s\n", hexOut(ckaID));
		SECITEM_FreeItem(ckaID, PR_TRUE);
	}

	if (privkey)
		SECKEY_DestroyPrivateKey(privkey);
	if (pubkey)
		SECKEY_DestroyPublicKey(pubkey);

	(void) NSS_Shutdown();
	(void) PR_Cleanup();
}