Ejemplo n.º 1
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()));
}
Ejemplo n.º 2
0
SECKEYPublicKey*
CryptoKey::PublicKeyFromJwk(const JsonWebKey& aJwk,
                            const nsNSSShutDownPreventionLock& /*proofOfLock*/)
{
  if (aJwk.mKty.EqualsLiteral(JWK_TYPE_RSA)) {
    // Verify that all of the required parameters are present
    CryptoBuffer n, e;
    if (!aJwk.mN.WasPassed() || NS_FAILED(n.FromJwkBase64(aJwk.mN.Value())) ||
        !aJwk.mE.WasPassed() || NS_FAILED(e.FromJwkBase64(aJwk.mE.Value()))) {
      return nullptr;
    }

    // Transcode to a DER RSAPublicKey structure
    struct RSAPublicKeyData {
      SECItem n;
      SECItem e;
    };
    const RSAPublicKeyData input = {
      { siUnsignedInteger, n.Elements(), (unsigned int) n.Length() },
      { siUnsignedInteger, e.Elements(), (unsigned int) e.Length() }
    };
    const SEC_ASN1Template rsaPublicKeyTemplate[] = {
      {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(RSAPublicKeyData)},
      {SEC_ASN1_INTEGER, offsetof(RSAPublicKeyData, n),},
      {SEC_ASN1_INTEGER, offsetof(RSAPublicKeyData, e),},
      {0,}
    };

    ScopedSECItem pkDer(SEC_ASN1EncodeItem(nullptr, nullptr, &input,
                                           rsaPublicKeyTemplate));
    if (!pkDer.get()) {
      return nullptr;
    }

    return SECKEY_ImportDERPublicKey(pkDer.get(), CKK_RSA);
  }

  if (aJwk.mKty.EqualsLiteral(JWK_TYPE_EC)) {
    // Verify that all of the required parameters are present
    CryptoBuffer x, y;
    if (!aJwk.mCrv.WasPassed() ||
        !aJwk.mX.WasPassed() || NS_FAILED(x.FromJwkBase64(aJwk.mX.Value())) ||
        !aJwk.mY.WasPassed() || NS_FAILED(y.FromJwkBase64(aJwk.mY.Value()))) {
      return nullptr;
    }

    ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
    if (!arena) {
      return nullptr;
    }

    SECKEYPublicKey* key = PORT_ArenaZNew(arena, SECKEYPublicKey);
    if (!key) {
      return nullptr;
    }

    key->keyType = ecKey;
    key->pkcs11Slot = nullptr;
    key->pkcs11ID = CK_INVALID_HANDLE;

    nsString namedCurve;
    if (!NormalizeToken(aJwk.mCrv.Value(), namedCurve)) {
      return nullptr;
    }

    // Create parameters.
    SECItem* params = CreateECParamsForCurve(namedCurve, arena.get());
    if (!params) {
      return nullptr;
    }
    key->u.ec.DEREncodedParams = *params;

    // Create point.
    SECItem* point = CreateECPointForCoordinates(x, y, arena.get());
    if (!point) {
      return nullptr;
    }
    key->u.ec.publicValue = *point;

    if (!PublicKeyValid(key)) {
      return nullptr;
    }

    return SECKEY_CopyPublicKey(key);
  }

  return nullptr;
}