SECKEYPrivateKey* CryptoKey::PrivateKeyFromJwk(const JsonWebKey& aJwk, const nsNSSShutDownPreventionLock& /*proofOfLock*/) { CK_OBJECT_CLASS privateKeyValue = CKO_PRIVATE_KEY; CK_BBOOL falseValue = CK_FALSE; if (aJwk.mKty.EqualsLiteral(JWK_TYPE_EC)) { // Verify that all of the required parameters are present CryptoBuffer x, y, d; if (!aJwk.mCrv.WasPassed() || !aJwk.mX.WasPassed() || NS_FAILED(x.FromJwkBase64(aJwk.mX.Value())) || !aJwk.mY.WasPassed() || NS_FAILED(y.FromJwkBase64(aJwk.mY.Value())) || !aJwk.mD.WasPassed() || NS_FAILED(d.FromJwkBase64(aJwk.mD.Value()))) { return nullptr; } nsString namedCurve; if (!NormalizeToken(aJwk.mCrv.Value(), namedCurve)) { return nullptr; } ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); if (!arena) { return nullptr; } // Create parameters. SECItem* params = CreateECParamsForCurve(namedCurve, arena.get()); if (!params) { return nullptr; } SECItem* ecPoint = CreateECPointForCoordinates(x, y, arena.get()); if (!ecPoint) { return nullptr; } // Compute the ID for this key // This is generated with a SHA-1 hash, so unlikely to collide ScopedSECItem objID(PK11_MakeIDFromPubKey(ecPoint)); if (!objID.get()) { return nullptr; } // Populate template from parameters CK_KEY_TYPE ecValue = CKK_EC; CK_ATTRIBUTE keyTemplate[9] = { { CKA_CLASS, &privateKeyValue, sizeof(privateKeyValue) }, { CKA_KEY_TYPE, &ecValue, sizeof(ecValue) }, { CKA_TOKEN, &falseValue, sizeof(falseValue) }, { CKA_SENSITIVE, &falseValue, sizeof(falseValue) }, { CKA_PRIVATE, &falseValue, sizeof(falseValue) }, { CKA_ID, objID->data, objID->len }, { CKA_EC_PARAMS, params->data, params->len }, { CKA_EC_POINT, ecPoint->data, ecPoint->len }, { CKA_VALUE, (void*) d.Elements(), d.Length() }, }; return PrivateKeyFromPrivateKeyTemplate(objID, keyTemplate, PR_ARRAY_SIZE(keyTemplate)); } if (aJwk.mKty.EqualsLiteral(JWK_TYPE_RSA)) { // Verify that all of the required parameters are present CryptoBuffer n, e, d, p, q, dp, dq, qi; if (!aJwk.mN.WasPassed() || NS_FAILED(n.FromJwkBase64(aJwk.mN.Value())) || !aJwk.mE.WasPassed() || NS_FAILED(e.FromJwkBase64(aJwk.mE.Value())) || !aJwk.mD.WasPassed() || NS_FAILED(d.FromJwkBase64(aJwk.mD.Value())) || !aJwk.mP.WasPassed() || NS_FAILED(p.FromJwkBase64(aJwk.mP.Value())) || !aJwk.mQ.WasPassed() || NS_FAILED(q.FromJwkBase64(aJwk.mQ.Value())) || !aJwk.mDp.WasPassed() || NS_FAILED(dp.FromJwkBase64(aJwk.mDp.Value())) || !aJwk.mDq.WasPassed() || NS_FAILED(dq.FromJwkBase64(aJwk.mDq.Value())) || !aJwk.mQi.WasPassed() || NS_FAILED(qi.FromJwkBase64(aJwk.mQi.Value()))) { return nullptr; } ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); if (!arena) { return nullptr; } // Compute the ID for this key // This is generated with a SHA-1 hash, so unlikely to collide SECItem nItem = { siBuffer, nullptr, 0 }; if (!n.ToSECItem(arena, &nItem)) { return nullptr; } ScopedSECItem objID(PK11_MakeIDFromPubKey(&nItem)); if (!objID.get()) { return nullptr; } // Populate template from parameters CK_KEY_TYPE rsaValue = CKK_RSA; CK_ATTRIBUTE keyTemplate[14] = { { CKA_CLASS, &privateKeyValue, sizeof(privateKeyValue) }, { CKA_KEY_TYPE, &rsaValue, sizeof(rsaValue) }, { CKA_TOKEN, &falseValue, sizeof(falseValue) }, { CKA_SENSITIVE, &falseValue, sizeof(falseValue) }, { CKA_PRIVATE, &falseValue, sizeof(falseValue) }, { CKA_ID, objID->data, objID->len }, { CKA_MODULUS, (void*) n.Elements(), n.Length() }, { CKA_PUBLIC_EXPONENT, (void*) e.Elements(), e.Length() }, { CKA_PRIVATE_EXPONENT, (void*) d.Elements(), d.Length() }, { CKA_PRIME_1, (void*) p.Elements(), p.Length() }, { CKA_PRIME_2, (void*) q.Elements(), q.Length() }, { CKA_EXPONENT_1, (void*) dp.Elements(), dp.Length() }, { CKA_EXPONENT_2, (void*) dq.Elements(), dq.Length() }, { CKA_COEFFICIENT, (void*) qi.Elements(), qi.Length() }, }; return PrivateKeyFromPrivateKeyTemplate(objID, keyTemplate, PR_ARRAY_SIZE(keyTemplate)); } return nullptr; }
/* * 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(); }
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; }
SECKEYPrivateKey* CryptoKey::PrivateKeyFromJwk(const JsonWebKey& aJwk, const nsNSSShutDownPreventionLock& /*proofOfLock*/) { if (!aJwk.mKty.WasPassed() || !aJwk.mKty.Value().EqualsLiteral(JWK_TYPE_RSA)) { return nullptr; } // Verify that all of the required parameters are present CryptoBuffer n, e, d, p, q, dp, dq, qi; if (!aJwk.mN.WasPassed() || NS_FAILED(n.FromJwkBase64(aJwk.mN.Value())) || !aJwk.mE.WasPassed() || NS_FAILED(e.FromJwkBase64(aJwk.mE.Value())) || !aJwk.mD.WasPassed() || NS_FAILED(d.FromJwkBase64(aJwk.mD.Value())) || !aJwk.mP.WasPassed() || NS_FAILED(p.FromJwkBase64(aJwk.mP.Value())) || !aJwk.mQ.WasPassed() || NS_FAILED(q.FromJwkBase64(aJwk.mQ.Value())) || !aJwk.mDp.WasPassed() || NS_FAILED(dp.FromJwkBase64(aJwk.mDp.Value())) || !aJwk.mDq.WasPassed() || NS_FAILED(dq.FromJwkBase64(aJwk.mDq.Value())) || !aJwk.mQi.WasPassed() || NS_FAILED(qi.FromJwkBase64(aJwk.mQi.Value()))) { return nullptr; } // Compute the ID for this key // This is generated with a SHA-1 hash, so unlikely to collide ScopedSECItem nItem(n.ToSECItem()); ScopedSECItem objID(PK11_MakeIDFromPubKey(nItem.get())); if (!nItem.get() || !objID.get()) { return nullptr; } // Populate template from parameters CK_OBJECT_CLASS privateKeyValue = CKO_PRIVATE_KEY; CK_KEY_TYPE rsaValue = CKK_RSA; CK_BBOOL falseValue = CK_FALSE; CK_ATTRIBUTE keyTemplate[14] = { { CKA_CLASS, &privateKeyValue, sizeof(privateKeyValue) }, { CKA_KEY_TYPE, &rsaValue, sizeof(rsaValue) }, { CKA_TOKEN, &falseValue, sizeof(falseValue) }, { CKA_SENSITIVE, &falseValue, sizeof(falseValue) }, { CKA_PRIVATE, &falseValue, sizeof(falseValue) }, { CKA_ID, objID->data, objID->len }, { CKA_MODULUS, (void*) n.Elements(), n.Length() }, { CKA_PUBLIC_EXPONENT, (void*) e.Elements(), e.Length() }, { CKA_PRIVATE_EXPONENT, (void*) d.Elements(), d.Length() }, { CKA_PRIME_1, (void*) p.Elements(), p.Length() }, { CKA_PRIME_2, (void*) q.Elements(), q.Length() }, { CKA_EXPONENT_1, (void*) dp.Elements(), dp.Length() }, { CKA_EXPONENT_2, (void*) dq.Elements(), dq.Length() }, { CKA_COEFFICIENT, (void*) qi.Elements(), qi.Length() }, }; // Create a generic object with the contents of the key ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); if (!slot.get()) { return nullptr; } ScopedPK11GenericObject obj(PK11_CreateGenericObject(slot.get(), keyTemplate, PR_ARRAY_SIZE(keyTemplate), PR_FALSE)); if (!obj.get()) { return nullptr; } // Have NSS translate the object to a private key by inspection // and make a copy we can own ScopedSECKEYPrivateKey privKey(PK11_FindKeyByKeyID(slot.get(), objID.get(), nullptr)); if (!privKey.get()) { return nullptr; } return SECKEY_CopyPrivateKey(privKey.get()); }