Пример #1
0
SECKEYPublicKey*
CryptoKey::PublicKeyFromSpki(CryptoBuffer& aKeyData,
                       const nsNSSShutDownPreventionLock& /*proofOfLock*/)
{
  ScopedSECItem spkiItem(aKeyData.ToSECItem());
  if (!spkiItem) {
    return nullptr;
  }

  ScopedCERTSubjectPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(spkiItem.get()));
  if (!spki) {
    return nullptr;
  }

  // Check for id-ecDH. Per the WebCrypto spec we must support it but NSS
  // does unfortunately not know about it. Let's change the algorithm to
  // id-ecPublicKey to make NSS happy.
  if (SECITEM_ItemsAreEqual(&SEC_OID_DATA_EC_DH, &spki->algorithm.algorithm)) {
    // Retrieve OID data for id-ecPublicKey (1.2.840.10045.2.1).
    SECOidData* oidData = SECOID_FindOIDByTag(SEC_OID_ANSIX962_EC_PUBLIC_KEY);
    if (!oidData) {
      return nullptr;
    }

    SECStatus rv = SECITEM_CopyItem(spki->arena, &spki->algorithm.algorithm,
                                    &oidData->oid);
    if (rv != SECSuccess) {
      return nullptr;
    }
  }

  return SECKEY_ExtractPublicKey(spki.get());
}
Пример #2
0
SECStatus
VerifySignedData(const CERTSignedData* sd, const CERTCertificate* cert,
                 void* pkcs11PinArg)
{
  if (!sd || !sd->data.data || !sd->signatureAlgorithm.algorithm.data ||
      !sd->signature.data || !cert) {
    PR_NOT_REACHED("invalid args to VerifySignedData");
    PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
    return SECFailure;
  }

  // See bug 921585.
  if (sd->data.len > static_cast<unsigned int>(std::numeric_limits<int>::max())) {
    PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
    return SECFailure;
  }

  // convert sig->len from bit counts to byte count.
  SECItem sig = sd->signature;
  DER_ConvertBitString(&sig);

  // Use SECKEY_ExtractPublicKey instead of CERT_ExtractPublicKey because
  // CERT_ExtractPublicKey would try to do (EC)DSA parameter inheritance, using
  // the classic (wrong) NSS path building logic. We intentionally do not
  // support parameter inheritance.
  ScopedSECKEYPublicKey
    pubKey(SECKEY_ExtractPublicKey(&cert->subjectPublicKeyInfo));
  if (!pubKey) {
    return SECFailure;
  }

  SECOidTag hashAlg;
  if (VFY_VerifyDataWithAlgorithmID(sd->data.data, static_cast<int>(sd->data.len),
                                    pubKey.get(), &sig, &sd->signatureAlgorithm,
                                    &hashAlg, pkcs11PinArg) != SECSuccess) {
    return SECFailure;
  }

  // TODO: Ideally, we would do this check before we call
  // VFY_VerifyDataWithAlgorithmID. But, VFY_VerifyDataWithAlgorithmID gives us
  // the hash algorithm so it is more convenient to do things in this order.
  uint32_t policy;
  if (NSS_GetAlgorithmPolicy(hashAlg, &policy) != SECSuccess) {
    return SECFailure;
  }

  // XXX: I'm not sure why there isn't NSS_USE_ALG_IN_SSL_SIGNATURE, but there
  // isn't. Since we don't know the context in which we're being called, be as
  // strict as we can be given the NSS API that is available.
  static const uint32_t requiredPolicy = NSS_USE_ALG_IN_CERT_SIGNATURE |
                                         NSS_USE_ALG_IN_CMS_SIGNATURE;
  if ((policy & requiredPolicy) != requiredPolicy) {
    PR_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, 0);
    return SECFailure;
  }

  return SECSuccess;
}
Пример #3
0
UniqueSECKEYPublicKey
CryptoKey::PublicKeyFromSpki(CryptoBuffer& aKeyData,
                       const nsNSSShutDownPreventionLock& /*proofOfLock*/)
{
  UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
  if (!arena) {
    return nullptr;
  }

  SECItem spkiItem = { siBuffer, nullptr, 0 };
  if (!aKeyData.ToSECItem(arena.get(), &spkiItem)) {
    return nullptr;
  }

  UniqueCERTSubjectPublicKeyInfo spki(
    SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem));
  if (!spki) {
    return nullptr;
  }

  bool isECDHAlgorithm = SECITEM_ItemsAreEqual(&SEC_OID_DATA_EC_DH,
                                               &spki->algorithm.algorithm);
  bool isDHAlgorithm = SECITEM_ItemsAreEqual(&SEC_OID_DATA_DH_KEY_AGREEMENT,
                                             &spki->algorithm.algorithm);

  // Check for |id-ecDH| and |dhKeyAgreement|. Per the WebCrypto spec we must
  // support these OIDs but NSS does unfortunately not know about them. Let's
  // change the algorithm to |id-ecPublicKey| or |dhPublicKey| to make NSS happy.
  if (isECDHAlgorithm || isDHAlgorithm) {
    SECOidTag oid = SEC_OID_UNKNOWN;
    if (isECDHAlgorithm) {
      oid = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
    } else if (isDHAlgorithm) {
      oid = SEC_OID_X942_DIFFIE_HELMAN_KEY;
    } else {
      MOZ_ASSERT(false);
    }

    SECOidData* oidData = SECOID_FindOIDByTag(oid);
    if (!oidData) {
      return nullptr;
    }

    SECStatus rv = SECITEM_CopyItem(spki->arena, &spki->algorithm.algorithm,
                                    &oidData->oid);
    if (rv != SECSuccess) {
      return nullptr;
    }
  }

  UniqueSECKEYPublicKey tmp(SECKEY_ExtractPublicKey(spki.get()));
  if (!tmp.get() || !PublicKeyValid(tmp.get())) {
    return nullptr;
  }

  return UniqueSECKEYPublicKey(SECKEY_CopyPublicKey(tmp.get()));
}
Пример #4
0
int
crypto_cert_get_pub_exp_mod(CryptoCert cert, uint32 * key_len,
		uint8 * exponent, uint32 exp_len, uint8 * modulus, uint32 mod_len)
{
	SECKEYPublicKey * pubkey;

	SECOidTag tag = SECOID_GetAlgorithmTag(&cert->cert->subjectPublicKeyInfo.algorithm);
	if ((tag == SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION) || (tag == SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE))
	{
		/* For some reason, Microsoft sets the OID of the Public RSA key to
		 the oid for "MD5 with RSA Encryption" instead of "RSA Encryption". */
		SECAlgorithmID org = cert->cert->subjectPublicKeyInfo.algorithm;
		SECStatus s = SECOID_SetAlgorithmID(cert->cert->subjectPublicKeyInfo.arena,
				&cert->cert->subjectPublicKeyInfo.algorithm,
				SEC_OID_PKCS1_RSA_ENCRYPTION, NULL);
		check(s, "Error setting temp algo oid");
		pubkey = SECKEY_ExtractPublicKey(&cert->cert->subjectPublicKeyInfo);
		SECOID_DestroyAlgorithmID(&cert->cert->subjectPublicKeyInfo.algorithm, False);
		cert->cert->subjectPublicKeyInfo.algorithm = org;
	}
	else
	{
		pubkey = SECKEY_ExtractPublicKey(&cert->cert->subjectPublicKeyInfo);
	}
	ASSERT(pubkey);
	ASSERT(pubkey->keyType == rsaKey);

	*key_len = SECKEY_PublicKeyStrength(pubkey);

	size_t l = pubkey->u.rsa.publicExponent.len;
	ASSERT(l <= exp_len);
	memset(exponent, 0, exp_len - l);
	memcpy(exponent + exp_len - l, pubkey->u.rsa.publicExponent.data, l);

	l = pubkey->u.rsa.modulus.len;
	ASSERT(l <= mod_len);
	ASSERT(*key_len <= mod_len);
	memset(modulus, 0, *key_len - l);
	memcpy(modulus + *key_len - l, pubkey->u.rsa.modulus.data, l);

	SECKEY_DestroyPublicKey(pubkey);
	return 0;
}
Пример #5
0
bool cert_key_is_rsa(CERTCertificate *cert)
{
	bool ret = FALSE;
	SECKEYPublicKey *pk = SECKEY_ExtractPublicKey(
					&cert->subjectPublicKeyInfo);

	if (pk != NULL) {
		ret = SECKEY_GetPublicKeyType(pk) == rsaKey;
		SECKEY_DestroyPublicKey(pk);
	}

	return ret;
}
Пример #6
0
static SECKEYPublicKey* getPublicKeyFromBytes(uint8_t *publicKeyBytes) {
  uint8_t spkiBytes[TACK_PUBKEY_LENGTH + sizeof(SPKI_P256)];
  memcpy(spkiBytes, SPKI_P256, sizeof(SPKI_P256));
  memcpy(spkiBytes + sizeof(SPKI_P256), publicKeyBytes, TACK_PUBKEY_LENGTH);

  SECItem spkiItem;
  spkiItem.data = spkiBytes;
  spkiItem.len  = sizeof(spkiBytes);

  CERTSubjectPublicKeyInfo *spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem);
  SECKEYPublicKey *publicKey     = SECKEY_ExtractPublicKey(spki);

  SECKEY_DestroySubjectPublicKeyInfo(spki);

  return publicKey;  
}
Пример #7
0
SECKEYPublicKey*
CryptoKey::PublicKeyFromSpki(CryptoBuffer& aKeyData,
                       const nsNSSShutDownPreventionLock& /*proofOfLock*/)
{
  ScopedSECItem spkiItem(aKeyData.ToSECItem());
  if (!spkiItem) {
    return nullptr;
  }

  ScopedCERTSubjectPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(spkiItem.get()));
  if (!spki) {
    return nullptr;
  }

  return SECKEY_ExtractPublicKey(spki.get());
}
Пример #8
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;
}
Пример #9
0
/*
 * FUNCTION: PKIX_PL_CRL_VerifySignature (see comments in pkix_pl_pki.h)
 */
PKIX_Error *
PKIX_PL_CRL_VerifySignature(
        PKIX_PL_CRL *crl,
        PKIX_PL_PublicKey *pubKey,
        void *plContext)
{
        PKIX_PL_CRL *cachedCrl = NULL;
        PKIX_Error *verifySig = NULL;
        PKIX_Error *cachedSig = NULL;
        PKIX_Boolean crlEqual = PKIX_FALSE;
        PKIX_Boolean crlInHash= PKIX_FALSE;
        CERTSignedCrl *nssSignedCrl = NULL;
        SECKEYPublicKey *nssPubKey = NULL;
        CERTSignedData *tbsCrl = NULL;
        void* wincx = NULL;
        SECStatus status;

        PKIX_ENTER(CRL, "PKIX_PL_CRL_VerifySignature");
        PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pubKey);

        /* Can call this function only with der been adopted. */
        PORT_Assert(crl->adoptedDerCrl);

        verifySig = PKIX_PL_HashTable_Lookup
                (cachedCrlSigTable,
                (PKIX_PL_Object *) pubKey,
                (PKIX_PL_Object **) &cachedCrl,
                plContext);

        if (cachedCrl != NULL && verifySig == NULL) {
                /* Cached Signature Table lookup succeed */
                PKIX_EQUALS(crl, cachedCrl, &crlEqual, plContext,
                            PKIX_OBJECTEQUALSFAILED);
                if (crlEqual == PKIX_TRUE) {
                        goto cleanup;
                }
                /* Different PubKey may hash to same value, skip add */
                crlInHash = PKIX_TRUE;
        }

        nssSignedCrl = crl->nssSignedCrl;
        tbsCrl = &nssSignedCrl->signatureWrap;

        PKIX_CRL_DEBUG("\t\tCalling SECKEY_ExtractPublicKey\n");
        nssPubKey = SECKEY_ExtractPublicKey(pubKey->nssSPKI);
        if (!nssPubKey){
                PKIX_ERROR(PKIX_SECKEYEXTRACTPUBLICKEYFAILED);
        }

        PKIX_CHECK(pkix_pl_NssContext_GetWincx
                   ((PKIX_PL_NssContext *)plContext, &wincx),
                   PKIX_NSSCONTEXTGETWINCXFAILED);

        PKIX_CRL_DEBUG("\t\tCalling CERT_VerifySignedDataWithPublicKey\n");
        status = CERT_VerifySignedDataWithPublicKey(tbsCrl, nssPubKey, wincx);

        if (status != SECSuccess) {
                PKIX_ERROR(PKIX_SIGNATUREDIDNOTVERIFYWITHTHEPUBLICKEY);
        }

        if (crlInHash == PKIX_FALSE) {
                cachedSig = PKIX_PL_HashTable_Add
                        (cachedCrlSigTable,
                        (PKIX_PL_Object *) pubKey,
                        (PKIX_PL_Object *) crl,
                        plContext);

                if (cachedSig != NULL) {
                        PKIX_DEBUG("PKIX_PL_HashTable_Add skipped: entry existed\n");
                }
        }

cleanup:

        if (nssPubKey){
                PKIX_CRL_DEBUG("\t\tCalling SECKEY_DestroyPublicKey\n");
                SECKEY_DestroyPublicKey(nssPubKey);
                nssPubKey = NULL;
        }

        PKIX_DECREF(cachedCrl);
        PKIX_DECREF(verifySig);
        PKIX_DECREF(cachedSig);

        PKIX_RETURN(CRL);
}
NS_IMETHODIMP
nsDataSignatureVerifier::VerifyData(const nsACString & aData,
                                    const nsACString & aSignature,
                                    const nsACString & aPublicKey,
                                    bool *_retval)
{
    // Allocate an arena to handle the majority of the allocations
    PRArenaPool *arena;
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    if (!arena)
        return NS_ERROR_OUT_OF_MEMORY;

    // Base 64 decode the key
    SECItem keyItem;
    PORT_Memset(&keyItem, 0, sizeof(SECItem));
    if (!NSSBase64_DecodeBuffer(arena, &keyItem,
                                nsPromiseFlatCString(aPublicKey).get(),
                                aPublicKey.Length())) {
        PORT_FreeArena(arena, false);
        return NS_ERROR_FAILURE;
    }
    
    // Extract the public key from the data
    CERTSubjectPublicKeyInfo *pki = SECKEY_DecodeDERSubjectPublicKeyInfo(&keyItem);
    if (!pki) {
        PORT_FreeArena(arena, false);
        return NS_ERROR_FAILURE;
    }
    SECKEYPublicKey *publicKey = SECKEY_ExtractPublicKey(pki);
    SECKEY_DestroySubjectPublicKeyInfo(pki);
    pki = nullptr;
    
    if (!publicKey) {
        PORT_FreeArena(arena, false);
        return NS_ERROR_FAILURE;
    }
    
    // Base 64 decode the signature
    SECItem signatureItem;
    PORT_Memset(&signatureItem, 0, sizeof(SECItem));
    if (!NSSBase64_DecodeBuffer(arena, &signatureItem,
                                nsPromiseFlatCString(aSignature).get(),
                                aSignature.Length())) {
        SECKEY_DestroyPublicKey(publicKey);
        PORT_FreeArena(arena, false);
        return NS_ERROR_FAILURE;
    }
    
    // Decode the signature and algorithm
    CERTSignedData sigData;
    PORT_Memset(&sigData, 0, sizeof(CERTSignedData));
    SECStatus ss = SEC_QuickDERDecodeItem(arena, &sigData, 
                                          CERT_SignatureDataTemplate,
                                          &signatureItem);
    if (ss != SECSuccess) {
        SECKEY_DestroyPublicKey(publicKey);
        PORT_FreeArena(arena, false);
        return NS_ERROR_FAILURE;
    }
    
    // Perform the final verification
    DER_ConvertBitString(&(sigData.signature));
    ss = VFY_VerifyDataWithAlgorithmID((const unsigned char*)nsPromiseFlatCString(aData).get(),
                                       aData.Length(), publicKey,
                                       &(sigData.signature),
                                       &(sigData.signatureAlgorithm),
                                       NULL, NULL);
    
    // Clean up remaining objects
    SECKEY_DestroyPublicKey(publicKey);
    PORT_FreeArena(arena, false);
    
    *_retval = (ss == SECSuccess);

    return NS_OK;
}