Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  pk11_import_unittest.cc

  Sprache: C
 

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */


#include <memory>
#include "nss.h"
#include "pk11pub.h"
#include "pk11pqg.h"
#include "prerror.h"
#include "secoid.h"

#include "cpputil.h"
#include "nss_scoped_ptrs.h"
#include "gtest/gtest.h"
#include "databuffer.h"
#include "pk11_import_vectors.h"
#include "pk11_keygen.h"

namespace nss_test {

// This deleter deletes a set of objects, unlike the deleter on
// ScopedPK11GenericObject, which only deletes one.
struct PK11GenericObjectsDeleter {
  void operator()(PK11GenericObject* objs) {
    if (objs) {
      PK11_DestroyGenericObjects(objs);
    }
  }
};

class Pk11KeyImportTestBase : public ::testing::Test {
 public:
  Pk11KeyImportTestBase() = default;
  virtual ~Pk11KeyImportTestBase() = default;

  void SetUp() override {
    slot_.reset(PK11_GetInternalKeySlot());
    ASSERT_TRUE(slot_);

    static const uint8_t pw[] = "pw";
    SECItem pwItem = {siBuffer, toUcharPtr(pw), sizeof(pw)};
    password_.reset(SECITEM_DupItem(&pwItem));
  }

  void Test(const Pkcs11KeyPairGenerator& generator) {
    // Generate a key and export it.
    KeyType key_type = nullKey;
    ScopedSECKEYEncryptedPrivateKeyInfo key_info;
    ScopedSECItem public_value;
    GenerateAndExport(generator, &key_type, &key_info, &public_value);

    // Note: NSS is currently unable export wrapped DH keys, so this doesn't
    // test those beyond generate and verify.
    if (key_type == dhKey) {
      return;
    }
#ifdef NSS_DISABLE_DSA
    // if DSA is disabled, we can't generate a key, Generated will
    // have expected a failure, and checked the error codeso we are now.
    if (generator.mechanism() == CKM_DSA_KEY_PAIR_GEN) {
      return;
    }
#endif
    ASSERT_NE(nullptr, public_value);
    ASSERT_NE(nullptr, key_info);

    // Now import the encrypted key.
    static const uint8_t nick[] = "nick";
    SECItem nickname = {siBuffer, toUcharPtr(nick), sizeof(nick)};
    SECKEYPrivateKey* priv_tmp;
    SECStatus rv = PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(
        slot_.get(), key_info.get(), password_.get(), &nickname,
        public_value.get(), PR_TRUE, PR_TRUE, key_type, 0, &priv_tmp, NULL);
    ASSERT_EQ(SECSuccess, rv) << "PK11_ImportEncryptedPrivateKeyInfo failed "
                              << PORT_ErrorToName(PORT_GetError());
    ScopedSECKEYPrivateKey priv_key(priv_tmp);
    ASSERT_NE(nullptr, priv_key);

    CheckForPublicKey(priv_key, public_value.get());
  }

 private:
  SECItem GetPublicComponent(ScopedSECKEYPublicKey& pub_key) {
    SECItem null = {siBuffer, NULL, 0};
    switch (SECKEY_GetPublicKeyType(pub_key.get())) {
      case rsaKey:
      case rsaPssKey:
      case rsaOaepKey:
        return pub_key->u.rsa.modulus;
      case keaKey:
        return pub_key->u.kea.publicValue;
      case dsaKey:
        return pub_key->u.dsa.publicValue;
      case dhKey:
        return pub_key->u.dh.publicValue;
      case ecKey:
      case edKey:
      case ecMontKey:
        return pub_key->u.ec.publicValue;
      case kyberKey:
        return pub_key->u.kyber.publicValue;
      case mldsaKey:    /* add import tests when pkcs #8 support is added */
      case fortezzaKey: /* depricated */
      case nullKey:
        /* didn't use default here so we can catch new key types at compile time
         */

        break;
    }
    return null;
  }
  void CheckForPublicKey(const ScopedSECKEYPrivateKey& priv_key,
                         const SECItem* expected_public) {
    // Verify the public key exists.
    StackSECItem priv_id;
    KeyType type = SECKEY_GetPrivateKeyType(priv_key.get());
    SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, priv_key.get(),
                                         CKA_ID, &priv_id);
    ASSERT_EQ(SECSuccess, rv) << "Couldn't read CKA_ID from private key: "
                              << PORT_ErrorToName(PORT_GetError());

    CK_ATTRIBUTE_TYPE value_type = CKA_VALUE;
    switch (type) {
      case rsaKey:
        value_type = CKA_MODULUS;
        break;

      case dhKey:
      case dsaKey:
        value_type = CKA_VALUE;
        break;

      case ecKey:
        value_type = CKA_EC_POINT;
        break;

      default:
        FAIL() << "unknown key type";
    }

    // Scan public key objects until we find one with the same CKA_ID as
    // priv_key
    std::unique_ptr<PK11GenericObject, PK11GenericObjectsDeleter> objs(
        PK11_FindGenericObjects(slot_.get(), CKO_PUBLIC_KEY));
    ASSERT_NE(nullptr, objs);
    for (PK11GenericObject* obj = objs.get(); obj != nullptr;
         obj = PK11_GetNextGenericObject(obj)) {
      StackSECItem pub_id;
      rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_ID, &pub_id);
      if (rv != SECSuccess) {
        // Can't read CKA_ID from object.
        continue;
      }
      if (!SECITEM_ItemsAreEqual(&priv_id, &pub_id)) {
        // This isn't the object we're looking for.
        continue;
      }

      StackSECItem token;
      rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_TOKEN, &token);
      ASSERT_EQ(SECSuccess, rv);
      ASSERT_EQ(1U, token.len);
      ASSERT_NE(0, token.data[0]);

      StackSECItem raw_value;
      SECItem decoded_value;
      rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, value_type, &raw_value);
      ASSERT_EQ(SECSuccess, rv);
      SECItem value = raw_value;

      // Decode the EC_POINT and check the output against expected.
      // CKA_EC_POINT isn't stable, see Bug 1520649.
      ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
      ASSERT_TRUE(arena);
      if (value_type == CKA_EC_POINT) {
        // If this fails due to the noted inconsistency, we may need to
        // check the whole raw_value, or remove a leading UNCOMPRESSED_POINT tag
        rv = SEC_QuickDERDecodeItem(arena.get(), &decoded_value,
                                    SEC_ASN1_GET(SEC_OctetStringTemplate),
                                    &raw_value);
        ASSERT_EQ(SECSuccess, rv);
        value = decoded_value;
      }
      ASSERT_TRUE(SECITEM_ItemsAreEqual(expected_public, &value))
          << "expected: "
          << DataBuffer(expected_public->data, expected_public->len)
          << std::endl
          << "actual: " << DataBuffer(value.data, value.len) << std::endl;

      // Finally, convert the private to public and ensure it matches.
      ScopedSECKEYPublicKey pub_key(SECKEY_ConvertToPublicKey(priv_key.get()));
      ASSERT_TRUE(pub_key);
      SECItem converted_public = GetPublicComponent(pub_key);
      ASSERT_TRUE(converted_public.len != 0);

      ASSERT_TRUE(SECITEM_ItemsAreEqual(expected_public, &converted_public))
          << "expected: "
          << DataBuffer(expected_public->data, expected_public->len)
          << std::endl
          << "actual: "
          << DataBuffer(converted_public.data, converted_public.len)
          << std::endl;
    }
  }

  void GenerateAndExport(const Pkcs11KeyPairGenerator& generator,
                         KeyType* key_type,
                         ScopedSECKEYEncryptedPrivateKeyInfo* key_info,
                         ScopedSECItem* public_value) {
    ScopedSECKEYPrivateKey priv_key;
    ScopedSECKEYPublicKey pub_key;
    generator.GenerateKey(&priv_key, &pub_key);
#ifdef NSS_DISABLE_DSA
    if (generator.mechanism() == CKM_DSA_KEY_PAIR_GEN) {
      ASSERT_FALSE(priv_key);
      return;
    }
#endif
    ASSERT_TRUE(priv_key);

    // Save the public value, which we will need on import
    SECItem* pub_val;
    KeyType t = SECKEY_GetPublicKeyType(pub_key.get());
    switch (t) {
      case rsaKey:
        pub_val = &pub_key->u.rsa.modulus;
        break;
      case dhKey:
        pub_val = &pub_key->u.dh.publicValue;
        break;
      case dsaKey:
        pub_val = &pub_key->u.dsa.publicValue;
        break;
      case ecKey:
        pub_val = &pub_key->u.ec.publicValue;
        break;
      default:
        FAIL() << "Unknown key type";
    }

    CheckForPublicKey(priv_key, pub_val);

    *key_type = t;
    // Note: NSS is currently unable export wrapped DH keys, so this doesn't
    // test those beyond generate and verify.
    if (t == dhKey) {
      return;
    }
    public_value->reset(SECITEM_DupItem(pub_val));

    // Wrap and export the key.
    ScopedSECKEYEncryptedPrivateKeyInfo epki(PK11_ExportEncryptedPrivKeyInfo(
        slot_.get(), SEC_OID_AES_256_CBC, password_.get(), priv_key.get(), 1,
        nullptr));
    ASSERT_NE(nullptr, epki) << "PK11_ExportEncryptedPrivKeyInfo failed: "
                             << PORT_ErrorToName(PORT_GetError());

    key_info->swap(epki);
  }

  ScopedPK11SlotInfo slot_;
  ScopedSECItem password_;
};

class Pk11KeyImportTest
    : public Pk11KeyImportTestBase,
      public ::testing::WithParamInterface<CK_MECHANISM_TYPE> {
 public:
  Pk11KeyImportTest() = default;
  virtual ~Pk11KeyImportTest() = default;
};

TEST_P(Pk11KeyImportTest, GenerateExportImport) {
  Test(Pkcs11KeyPairGenerator(GetParam()));
}

// we go ahead and test for DSA, this only trigger key gen, which will
// check that we fail with a proper error code
INSTANTIATE_TEST_SUITE_P(Pk11KeyImportTest, Pk11KeyImportTest,
                         ::testing::Values(CKM_RSA_PKCS_KEY_PAIR_GEN,
                                           CKM_DSA_KEY_PAIR_GEN,
                                           CKM_DH_PKCS_KEY_PAIR_GEN));

class Pk11KeyImportTestEC : public Pk11KeyImportTestBase,
                            public ::testing::WithParamInterface<SECOidTag> {
 public:
  Pk11KeyImportTestEC() = default;
  virtual ~Pk11KeyImportTestEC() = default;
};

TEST_P(Pk11KeyImportTestEC, GenerateExportImport) {
  Test(Pkcs11KeyPairGenerator(CKM_EC_KEY_PAIR_GEN, GetParam()));
}

INSTANTIATE_TEST_SUITE_P(Pk11KeyImportTestEC, Pk11KeyImportTestEC,
                         ::testing::Values(SEC_OID_SECG_EC_SECP256R1,
                                           SEC_OID_SECG_EC_SECP384R1,
                                           SEC_OID_SECG_EC_SECP521R1,
                                           SEC_OID_CURVE25519));

struct Pkcs11CompressedECKeyTestParams {
  DataBuffer compressedKey;
  DataBuffer uncompressedKey;
};

class Pk11KeyImportTestECCompressed
    : public Pk11KeyImportTestBase,
      public ::testing::WithParamInterface<Pkcs11CompressedECKeyTestParams> {
 public:
  Pk11KeyImportTestECCompressed() = default;
  virtual ~Pk11KeyImportTestECCompressed() = default;
};

// Importing a private key in PKCS#8 format with a point not on the curve will
// succeed. Using the contained public key however will fail when trying to
// import it before using it for any operation.
TEST_P(Pk11KeyImportTestECCompressed, CompressedPointTest) {
  DataBuffer spki(GetParam().compressedKey);
  SECItem spki_item = {siBuffer, toUcharPtr(spki.data()),
                       static_cast<unsigned int>(spki.len())};

  ScopedCERTSubjectPublicKeyInfo cert_spki(
      SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
  ASSERT_TRUE(cert_spki);
  ScopedSECKEYPublicKey pub_key(SECKEY_ExtractPublicKey(cert_spki.get()));
  ASSERT_TRUE(pub_key);

  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
  ASSERT_TRUE(slot);

  CK_OBJECT_HANDLE id =
      PK11_ImportPublicKey(slot.get(), pub_key.get(), PR_FALSE);
  ASSERT_NE(id, (unsigned int)CK_INVALID_HANDLE);

  StackSECItem publicDecoded;
  SECStatus rv = PK11_ReadRawAttribute(PK11_TypePubKey, pub_key.get(),
                                       CKA_EC_POINT, &publicDecoded);
  ASSERT_EQ(rv, SECSuccess);

  ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
  ASSERT_TRUE(arena);

  SECItem decodedItem;
  rv = SEC_QuickDERDecodeItem(arena.get(), &decodedItem,
                              SEC_ASN1_GET(SEC_OctetStringTemplate),
                              &publicDecoded);

  ASSERT_EQ(rv, SECSuccess);
  ASSERT_EQ(decodedItem.len, GetParam().uncompressedKey.len());
  ASSERT_EQ(0, PORT_Memcmp(decodedItem.data, GetParam().uncompressedKey.data(),
                           decodedItem.len));
};

static const Pkcs11CompressedECKeyTestParams kCompressedVectors[] = {
    {DataBuffer(kP256CompressedSpki, sizeof(kP256CompressedSpki)),
     DataBuffer(kP256Uncompressed, sizeof(kP256Uncompressed))},
    {DataBuffer(kP384CompressedSpki, sizeof(kP384CompressedSpki)),
     DataBuffer(kP384Uncompressed, sizeof(kP384Uncompressed))},
    {DataBuffer(kP521CompressedSpki, sizeof(kP521CompressedSpki)),
     DataBuffer(kP521Uncompressed, sizeof(kP521Uncompressed))}};

INSTANTIATE_TEST_SUITE_P(Pk11KeyImportTestECCompressed,
                         Pk11KeyImportTestECCompressed,
                         ::testing::ValuesIn(kCompressedVectors));

// Importing a key with 0x7 sign value instead of 0x02/0x03
TEST_F(Pk11KeyImportTestEC, CompressedPointWrongSign) {
  DataBuffer spki(kP256CompressedSpkiWrongSign,
                  sizeof(kP256CompressedSpkiWrongSign));
  SECItem spki_item = {siBuffer, toUcharPtr(spki.data()),
                       static_cast<unsigned int>(spki.len())};

  ScopedCERTSubjectPublicKeyInfo cert_spki(
      SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
  ASSERT_TRUE(cert_spki);
  ScopedSECKEYPublicKey pub_key(SECKEY_ExtractPublicKey(cert_spki.get()));
  ASSERT_TRUE(pub_key);

  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
  ASSERT_TRUE(slot);

  CK_OBJECT_HANDLE id =
      PK11_ImportPublicKey(slot.get(), pub_key.get(), PR_FALSE);
  ASSERT_EQ(id, (unsigned int)CK_INVALID_HANDLE);
}

TEST_F(Pk11KeyImportTestEC, CompressedPointWrongLen) {
  DataBuffer spki(kP256CompressedSpkiWrongPointLength,
                  sizeof(kP256CompressedSpkiWrongPointLength));
  SECItem spki_item = {siBuffer, toUcharPtr(spki.data()),
                       static_cast<unsigned int>(spki.len())};

  ScopedCERTSubjectPublicKeyInfo cert_spki(
      SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
  ASSERT_FALSE(cert_spki);
}

TEST_F(Pk11KeyImportTestEC, CompressedPointNotOnCurve) {
  DataBuffer spki(kP256CompressedSpkiNotOnCurve,
                  sizeof(kP256CompressedSpkiNotOnCurve));
  SECItem spki_item = {siBuffer, toUcharPtr(spki.data()),
                       static_cast<unsigned int>(spki.len())};

  ScopedCERTSubjectPublicKeyInfo cert_spki(
      SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
  ASSERT_TRUE(cert_spki);
  ScopedSECKEYPublicKey pub_key(SECKEY_ExtractPublicKey(cert_spki.get()));
  ASSERT_TRUE(pub_key);

  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
  ASSERT_TRUE(slot);

  CK_OBJECT_HANDLE id =
      PK11_ImportPublicKey(slot.get(), pub_key.get(), PR_FALSE);
  ASSERT_NE(id, (unsigned int)CK_INVALID_HANDLE);
}

}  // namespace nss_test

Messung V0.5 in Prozent
C=93 H=89 G=90

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002