Ejemplo n.º 1
0
/* Find the "weakest link".  Get the strength of the signature and symmetric
 * keys and choose a curve based on the weakest of those two. */
const sslNamedGroupDef *
ssl_GetECGroupForServerSocket(sslSocket *ss)
{
    const sslServerCert *cert = ss->sec.serverCert;
    unsigned int certKeySize;
    const ssl3BulkCipherDef *bulkCipher;
    unsigned int requiredECCbits;

    PORT_Assert(cert);
    if (!cert || !cert->serverKeyPair || !cert->serverKeyPair->pubKey) {
        PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
        return NULL;
    }

    if (cert->certType.authType == ssl_auth_rsa_sign) {
        certKeySize = SECKEY_PublicKeyStrengthInBits(cert->serverKeyPair->pubKey);
        certKeySize =
            SSL_RSASTRENGTH_TO_ECSTRENGTH(certKeySize);
    } else if (cert->certType.authType == ssl_auth_ecdsa ||
               cert->certType.authType == ssl_auth_ecdh_rsa ||
               cert->certType.authType == ssl_auth_ecdh_ecdsa) {
        const sslNamedGroupDef *groupDef = cert->certType.namedCurve;

        /* We won't select a certificate unless the named curve has been
         * negotiated (or supported_curves was absent), double check that. */
        PORT_Assert(groupDef->keaType == ssl_kea_ecdh);
        PORT_Assert(ssl_NamedGroupEnabled(ss, groupDef));
        if (!ssl_NamedGroupEnabled(ss, groupDef)) {
            return NULL;
        }
        certKeySize = groupDef->bits;
    } else {
        PORT_Assert(0);
        return NULL;
    }
    bulkCipher = ssl_GetBulkCipherDef(ss->ssl3.hs.suite_def);
    requiredECCbits = bulkCipher->key_size * BPB * 2;
    PORT_Assert(requiredECCbits ||
                ss->ssl3.hs.suite_def->bulk_cipher_alg == cipher_null);
    if (requiredECCbits > certKeySize) {
        requiredECCbits = certKeySize;
    }

    return ssl_GetECGroupWithStrength(ss, requiredECCbits);
}
Ejemplo n.º 2
0
SECStatus
CheckPublicKeySize(const SECItem& subjectPublicKeyInfo,
                   /*out*/ ScopedSECKeyPublicKey& publicKey)
{
  ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo>
    spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&subjectPublicKeyInfo));
  if (!spki) {
    return SECFailure;
  }
  publicKey = SECKEY_ExtractPublicKey(spki.get());
  if (!publicKey) {
    return SECFailure;
  }

  static const unsigned int MINIMUM_NON_ECC_BITS = 1024;

  switch (publicKey.get()->keyType) {
    case ecKey:
      // TODO(bug 622859): We should check which curve.
      return SECSuccess;
    case dsaKey: // fall through
    case rsaKey:
      // TODO(bug 622859): Enforce a minimum of 2048 bits for EV certs.
      if (SECKEY_PublicKeyStrengthInBits(publicKey.get()) < MINIMUM_NON_ECC_BITS) {
        // TODO(bug 1031946): Create a new error code.
        PR_SetError(SEC_ERROR_INVALID_KEY, 0);
        return SECFailure;
      }
      break;
    case nullKey:
    case fortezzaKey:
    case dhKey:
    case keaKey:
    case rsaPssKey:
    case rsaOaepKey:
    default:
      PR_SetError(SEC_ERROR_UNSUPPORTED_KEYALG, 0);
      return SECFailure;
  }

  return SECSuccess;
}
Ejemplo n.º 3
0
static SECStatus
ssl_PopulateKeyPair(sslServerCert *sc, sslKeyPair *keyPair)
{
    /* Copy over the key pair. */
    if (sc->serverKeyPair) {
        ssl_FreeKeyPair(sc->serverKeyPair);
    }
    if (keyPair) {
        /* Get the size of the cert's public key, and remember it. */
        sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->pubKey);
        if (sc->serverKeyBits == 0) {
            return SECFailure;
        }

        SECKEY_CacheStaticFlags(keyPair->privKey);
        sc->serverKeyPair = ssl_GetKeyPairRef(keyPair);
    } else {
        sc->serverKeyPair = NULL;
    }
    return SECSuccess;
}
Ejemplo n.º 4
0
/* Find the "weakest link".  Get the strength of the signature and symmetric
 * keys and choose a curve based on the weakest of those two. */
const namedGroupDef *
ssl_GetECGroupForServerSocket(sslSocket *ss)
{
    const sslServerCert *cert = ss->sec.serverCert;
    int certKeySize;
    int requiredECCbits = ss->sec.secretKeyBits * 2;

    PORT_Assert(cert);
    if (!cert || !cert->serverKeyPair || !cert->serverKeyPair->pubKey) {
        PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
        return NULL;
    }

    if (cert->certType.authType == ssl_auth_rsa_sign) {
        certKeySize = SECKEY_PublicKeyStrengthInBits(cert->serverKeyPair->pubKey);
        certKeySize =
            SSL_RSASTRENGTH_TO_ECSTRENGTH(certKeySize);
    } else if (cert->certType.authType == ssl_auth_ecdsa ||
               cert->certType.authType == ssl_auth_ecdh_rsa ||
               cert->certType.authType == ssl_auth_ecdh_ecdsa) {
        const namedGroupDef *groupDef = cert->certType.namedCurve;

        /* We won't select a certificate unless the named curve has been
         * negotiated (or supported_curves was absent), double check that. */
        PORT_Assert(groupDef->type == group_type_ec);
        PORT_Assert(ssl_NamedGroupEnabled(ss, groupDef));
        if (!ssl_NamedGroupEnabled(ss, groupDef)) {
            return NULL;
        }
        certKeySize = groupDef->bits;
    } else {
        PORT_Assert(0);
        return NULL;
    }
    if (requiredECCbits > certKeySize) {
        requiredECCbits = certKeySize;
    }

    return ssl_GetECGroupWithStrength(ss->namedGroups, requiredECCbits);
}
Ejemplo n.º 5
0
SECStatus
ssl_ConfigSecureServer(sslSocket *ss, CERTCertificate *cert,
                       const CERTCertificateList *certChain,
                       ssl3KeyPair *keyPair, SSLKEAType kea)
{
    CERTCertificateList *localCertChain = NULL;
    sslServerCerts  *sc = ss->serverCerts + kea;

    /* load the server certificate */
    if (sc->serverCert != NULL) {
	CERT_DestroyCertificate(sc->serverCert);
    	sc->serverCert = NULL;
        sc->serverKeyBits = 0;
    }
    /* load the server cert chain */
    if (sc->serverCertChain != NULL) {
	CERT_DestroyCertificateList(sc->serverCertChain);
    	sc->serverCertChain = NULL;
    }
    if (cert) {
        sc->serverCert = CERT_DupCertificate(cert);
        /* get the size of the cert's public key, and remember it */
        sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->pubKey);
        if (!certChain) {
            localCertChain =
                CERT_CertChainFromCert(sc->serverCert, certUsageSSLServer,
                                       PR_TRUE);
            if (!localCertChain)
                goto loser;
        }
        sc->serverCertChain = (certChain) ? CERT_DupCertList(certChain) :
                                            localCertChain;
        if (!sc->serverCertChain) {
            goto loser;
        }
        localCertChain = NULL;      /* consumed */
    }

    /* get keyPair */
    if (sc->serverKeyPair != NULL) {
        ssl3_FreeKeyPair(sc->serverKeyPair);
        sc->serverKeyPair = NULL;
    }
    if (keyPair) {
        SECKEY_CacheStaticFlags(keyPair->privKey);
        sc->serverKeyPair = ssl3_GetKeyPairRef(keyPair);
    }
    if (kea == kt_rsa && cert && sc->serverKeyBits > 512 &&
        !ss->opt.noStepDown && !ss->stepDownKeyPair) { 
        if (ssl3_CreateRSAStepDownKeys(ss) != SECSuccess) {
            goto loser;
        }
    }
    return SECSuccess;

loser:
    if (localCertChain) {
        CERT_DestroyCertificateList(localCertChain);
    }
    if (sc->serverCert != NULL) {
	CERT_DestroyCertificate(sc->serverCert);
	sc->serverCert = NULL;
    }
    if (sc->serverCertChain != NULL) {
	CERT_DestroyCertificateList(sc->serverCertChain);
	sc->serverCertChain = NULL;
    }
    if (sc->serverKeyPair != NULL) {
	ssl3_FreeKeyPair(sc->serverKeyPair);
	sc->serverKeyPair = NULL;
    }
    return SECFailure;
}
Ejemplo n.º 6
0
/*
 * smime_choose_cipher - choose a cipher that works for all the recipients
 *
 * "scert"  - sender's certificate
 * "rcerts" - recipient's certificates
 */
static long
smime_choose_cipher(CERTCertificate *scert, CERTCertificate **rcerts)
{
    PLArenaPool *poolp;
    long cipher;
    long chosen_cipher;
    int *cipher_abilities;
    int *cipher_votes;
    int weak_mapi;
    int strong_mapi;
    int aes128_mapi;
    int aes256_mapi;
    int rcount, mapi, max, i;

    chosen_cipher = SMIME_RC2_CBC_40;		/* the default, LCD */
    weak_mapi = smime_mapi_by_cipher(chosen_cipher);
    aes128_mapi = smime_mapi_by_cipher(SMIME_AES_CBC_128);
    aes256_mapi = smime_mapi_by_cipher(SMIME_AES_CBC_256);

    poolp = PORT_NewArena (1024);		/* XXX what is right value? */
    if (poolp == NULL)
	goto done;

    cipher_abilities = (int *)PORT_ArenaZAlloc(poolp, smime_cipher_map_count * sizeof(int));
    cipher_votes     = (int *)PORT_ArenaZAlloc(poolp, smime_cipher_map_count * sizeof(int));
    if (cipher_votes == NULL || cipher_abilities == NULL)
	goto done;

    /* Make triple-DES the strong cipher. */
    strong_mapi = smime_mapi_by_cipher (SMIME_DES_EDE3_168);

    /* walk all the recipient's certs */
    for (rcount = 0; rcerts[rcount] != NULL; rcount++) {
	SECItem *profile;
	NSSSMIMECapability **caps;
	int pref;

	/* the first cipher that matches in the user's SMIME profile gets
	 * "smime_cipher_map_count" votes; the next one gets "smime_cipher_map_count" - 1
	 * and so on. If every cipher matches, the last one gets 1 (one) vote */
	pref = smime_cipher_map_count;

	/* find recipient's SMIME profile */
	profile = CERT_FindSMimeProfile(rcerts[rcount]);

	if (profile != NULL && profile->data != NULL && profile->len > 0) {
	    /* we have a profile (still DER-encoded) */
	    caps = NULL;
	    /* decode it */
	    if (SEC_QuickDERDecodeItem(poolp, &caps,
                    NSSSMIMECapabilitiesTemplate, profile) == SECSuccess &&
		    caps != NULL)
	    {
		/* walk the SMIME capabilities for this recipient */
		for (i = 0; caps[i] != NULL; i++) {
		    cipher = nss_SMIME_FindCipherForSMIMECap(caps[i]);
		    mapi = smime_mapi_by_cipher(cipher);
		    if (mapi >= 0) {
			/* found the cipher */
			cipher_abilities[mapi]++;
			cipher_votes[mapi] += pref;
			--pref;
		    }
		}
	    }
	} else {
	    /* no profile found - so we can only assume that the user can do
	     * the mandatory algorithms which are RC2-40 (weak crypto) and
	     * 3DES (strong crypto), unless the user has an elliptic curve
	     * key.  For elliptic curve keys, RFC 5753 mandates support
	     * for AES 128 CBC. */
	    SECKEYPublicKey *key;
	    unsigned int pklen_bits;
	    KeyType key_type;

	    /*
	     * if recipient's public key length is > 512, vote for a strong cipher
	     * please not that the side effect of this is that if only one recipient
	     * has an export-level public key, the strong cipher is disabled.
	     *
	     * XXX This is probably only good for RSA keys.  What I would
	     * really like is a function to just say;  Is the public key in
	     * this cert an export-length key?  Then I would not have to
	     * know things like the value 512, or the kind of key, or what
	     * a subjectPublicKeyInfo is, etc.
	     */
	    key = CERT_ExtractPublicKey(rcerts[rcount]);
	    pklen_bits = 0;
	    key_type = nullKey;
	    if (key != NULL) {
		pklen_bits = SECKEY_PublicKeyStrengthInBits (key);
		key_type = SECKEY_GetPublicKeyType(key);
		SECKEY_DestroyPublicKey (key);
		key = NULL;
	    }

	    if (key_type == ecKey) {
		/* While RFC 5753 mandates support for AES-128 CBC, should use
		 * AES 256 if user's key provides more than 128 bits of
		 * security strength so that symmetric key is not weak link. */

		/* RC2-40 is not compatible with elliptic curve keys. */
		chosen_cipher = SMIME_DES_EDE3_168;
		if (pklen_bits > 256) {
		    cipher_abilities[aes256_mapi]++;
		    cipher_votes[aes256_mapi] += pref;
		    pref--;
		}
		cipher_abilities[aes128_mapi]++;
		cipher_votes[aes128_mapi] += pref;
		pref--;
		cipher_abilities[strong_mapi]++;
		cipher_votes[strong_mapi] += pref;
		pref--;
	    } else {
		if (pklen_bits > 512) {
		    /* cast votes for the strong algorithm */
		    cipher_abilities[strong_mapi]++;
		    cipher_votes[strong_mapi] += pref;
		    pref--;
		}

		/* always cast (possibly less) votes for the weak algorithm */
		cipher_abilities[weak_mapi]++;
		cipher_votes[weak_mapi] += pref;
	    } 
	}
	if (profile != NULL)
	    SECITEM_FreeItem(profile, PR_TRUE);
    }

    /* find cipher that is agreeable by all recipients and that has the most votes */
    max = 0;
    for (mapi = 0; mapi < smime_cipher_map_count; mapi++) {
	/* if not all of the recipients can do this, forget it */
	if (cipher_abilities[mapi] != rcount)
	    continue;
	/* if cipher is not enabled or not allowed by policy, forget it */
	if (!smime_cipher_map[mapi].enabled || !smime_cipher_map[mapi].allowed)
	    continue;
	/* now see if this one has more votes than the last best one */
	if (cipher_votes[mapi] >= max) {
	    /* if equal number of votes, prefer the ones further down in the list */
	    /* with the expectation that these are higher rated ciphers */
	    chosen_cipher = smime_cipher_map[mapi].cipher;
	    max = cipher_votes[mapi];
	}
    }
    /* if no common cipher was found, chosen_cipher stays at the default */

done:
    if (poolp != NULL)
	PORT_FreeArena (poolp, PR_FALSE);

    return chosen_cipher;
}
Ejemplo n.º 7
0
SECStatus
SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert,
		       SECKEYPrivateKey *key, SSL3KEAType kea)
{
    SECStatus rv;
    sslSocket *ss;
    sslServerCerts  *sc;
    SECKEYPublicKey * pubKey = NULL;

    ss = ssl_FindSocket(fd);
    if (!ss) {
	return SECFailure;
    }

    /* Both key and cert must have a value or be NULL */
    /* Passing a value of NULL will turn off key exchange algorithms that were
     * previously turned on */
    if (!cert != !key) {
	PORT_SetError(SEC_ERROR_INVALID_ARGS);
	return SECFailure;
    }

    /* make sure the key exchange is recognized */
    if ((kea >= kt_kea_size) || (kea < kt_null)) {
	PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
	return SECFailure;
    }

    if (kea != ssl_FindCertKEAType(cert)) {
    	PORT_SetError(SSL_ERROR_CERT_KEA_MISMATCH);
	return SECFailure;
    }

    sc = ss->serverCerts + kea;
    /* load the server certificate */
    if (sc->serverCert != NULL) {
	CERT_DestroyCertificate(sc->serverCert);
    	sc->serverCert = NULL;
    }
    if (cert) {
	sc->serverCert = CERT_DupCertificate(cert);
	if (!sc->serverCert)
	    goto loser;
    	/* get the size of the cert's public key, and remember it */
	pubKey = CERT_ExtractPublicKey(cert);
	if (!pubKey) 
	    goto loser;
	sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(pubKey);
    }


    /* load the server cert chain */
    if (sc->serverCertChain != NULL) {
	CERT_DestroyCertificateList(sc->serverCertChain);
    	sc->serverCertChain = NULL;
    }
    if (cert) {
	sc->serverCertChain = CERT_CertChainFromCert(
			    sc->serverCert, certUsageSSLServer, PR_TRUE);
	if (sc->serverCertChain == NULL)
	     goto loser;
    }

    /* load the private key */
    if (sc->serverKeyPair != NULL) {
        ssl3_FreeKeyPair(sc->serverKeyPair);
        sc->serverKeyPair = NULL;
    }
    if (key) {
	SECKEYPrivateKey * keyCopy	= NULL;
	CK_MECHANISM_TYPE  keyMech	= CKM_INVALID_MECHANISM;

	if (key->pkcs11Slot) {
	    PK11SlotInfo * bestSlot;
	    bestSlot = PK11_ReferenceSlot(key->pkcs11Slot);
	    if (bestSlot) {
		keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key);
		PK11_FreeSlot(bestSlot);
	    }
	}
	if (keyCopy == NULL)
	    keyMech = PK11_MapSignKeyType(key->keyType);
	if (keyMech != CKM_INVALID_MECHANISM) {
	    PK11SlotInfo * bestSlot;
	    /* XXX Maybe should be bestSlotMultiple? */
	    bestSlot = PK11_GetBestSlot(keyMech, NULL /* wincx */);
	    if (bestSlot) {
		keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key);
		PK11_FreeSlot(bestSlot);
	    }
	}
	if (keyCopy == NULL)
	    keyCopy = SECKEY_CopyPrivateKey(key);
	if (keyCopy == NULL)
	    goto loser;
	SECKEY_CacheStaticFlags(keyCopy);
        sc->serverKeyPair = ssl3_NewKeyPair(keyCopy, pubKey);
        if (sc->serverKeyPair == NULL) {
            SECKEY_DestroyPrivateKey(keyCopy);
            goto loser;
        }
	pubKey = NULL; /* adopted by serverKeyPair */
    }

    if (kea == kt_rsa && cert && sc->serverKeyBits > 512) {
	if (ss->opt.noStepDown) {
	    /* disable all export ciphersuites */
	} else {
	    rv = ssl3_CreateRSAStepDownKeys(ss);
	    if (rv != SECSuccess) {
		return SECFailure; /* err set by ssl3_CreateRSAStepDownKeys */
	    }
	}
    }

    /* Only do this once because it's global. */
    if (PR_SUCCESS == PR_CallOnceWithArg(&setupServerCAListOnce, 
                                         &serverCAListSetup,
                                         (void *)(ss->dbHandle))) {
	return SECSuccess;
    }

loser:
    if (pubKey) {
	SECKEY_DestroyPublicKey(pubKey); 
	pubKey = NULL;
    }
    if (sc->serverCert != NULL) {
	CERT_DestroyCertificate(sc->serverCert);
	sc->serverCert = NULL;
    }
    if (sc->serverCertChain != NULL) {
	CERT_DestroyCertificateList(sc->serverCertChain);
	sc->serverCertChain = NULL;
    }
    if (sc->serverKeyPair != NULL) {
	ssl3_FreeKeyPair(sc->serverKeyPair);
	sc->serverKeyPair = NULL;
    }
    return SECFailure;
}