tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pk11_x25519_unittest.cc (12937B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include <memory>
      6 #include "nss.h"
      7 
      8 #include "json_reader.h"
      9 #include "nss_scoped_ptrs.h"
     10 
     11 #include "cpputil.h"
     12 #include "pk11_x25519_vectors.h"
     13 #include "pk11_signature_test.h"
     14 #include "pk11_keygen.h"
     15 
     16 namespace nss_test {
     17 
     18 // For test vectors.
     19 struct Pkcs11X25519ImportParams {
     20  const DataBuffer pkcs8_;
     21  const DataBuffer spki_;
     22 };
     23 
     24 static const Pkcs11X25519ImportParams kX25519Vectors[] = {
     25    {
     26        DataBuffer(kX25519Pkcs8_1, sizeof(kX25519Pkcs8_1)),
     27        DataBuffer(kX25519Spki_1, sizeof(kX25519Spki_1)),
     28    },
     29 };
     30 
     31 class Pkcs11X25519Test
     32    : public ::testing::Test,
     33      public ::testing::WithParamInterface<Pkcs11X25519ImportParams> {
     34 protected:
     35  ScopedSECKEYPrivateKey ImportPrivateKey(const DataBuffer& pkcs8) {
     36    ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
     37    if (!slot) {
     38      ADD_FAILURE() << "No slot";
     39      return nullptr;
     40    }
     41 
     42    SECItem pkcs8Item = {siBuffer, toUcharPtr(pkcs8.data()),
     43                         static_cast<unsigned int>(pkcs8.len())};
     44 
     45    SECKEYPrivateKey* key = nullptr;
     46    SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
     47        slot.get(), &pkcs8Item, nullptr, nullptr, false, false, KU_ALL, &key,
     48        nullptr);
     49 
     50    if (rv != SECSuccess) {
     51      return nullptr;
     52    }
     53 
     54    return ScopedSECKEYPrivateKey(key);
     55  }
     56 
     57  bool ExportPrivateKey(ScopedSECKEYPrivateKey* key, DataBuffer& pkcs8) {
     58    ScopedSECItem pkcs8Item(PK11_ExportDERPrivateKeyInfo(key->get(), nullptr));
     59    if (!pkcs8Item) {
     60      return false;
     61    }
     62    pkcs8.Assign(pkcs8Item->data, pkcs8Item->len);
     63    return true;
     64  }
     65 
     66  ScopedSECKEYPublicKey ImportPublicKey(const DataBuffer& spki) {
     67    SECItem spkiItem = {siBuffer, toUcharPtr(spki.data()),
     68                        static_cast<unsigned int>(spki.len())};
     69 
     70    ScopedCERTSubjectPublicKeyInfo certSpki(
     71        SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem));
     72    if (!certSpki) {
     73      return nullptr;
     74    }
     75 
     76    return ScopedSECKEYPublicKey(SECKEY_ExtractPublicKey(certSpki.get()));
     77  }
     78 
     79  bool CheckAlgIsX25519(SECItem* algorithm) {
     80    SECOidTag tag = SECOID_FindOIDTag(algorithm);
     81    if (tag != SEC_OID_X25519) {
     82      return false;
     83    }
     84 
     85    return true;
     86  }
     87 };
     88 
     89 TEST_P(Pkcs11X25519Test, ImportExportPkcs8) {
     90  DataBuffer exported;
     91  ScopedSECKEYPrivateKey key = ImportPrivateKey(GetParam().pkcs8_);
     92  EXPECT_EQ(key.get()->keyType, ecMontKey);
     93 
     94  SECKEYPrivateKeyInfo* pkInfo = PK11_ExportPrivKeyInfo(key.get(), nullptr);
     95  ASSERT_TRUE(pkInfo);
     96  /* empty parameters for X25519*/
     97  ASSERT_EQ(pkInfo->algorithm.parameters.len, (unsigned int)0);
     98  ASSERT_TRUE(CheckAlgIsX25519(&pkInfo->algorithm.algorithm));
     99  ExportPrivateKey(&key, exported);
    100  EXPECT_EQ(GetParam().pkcs8_, exported);
    101 
    102  SECKEY_DestroyPrivateKeyInfo(pkInfo, PR_TRUE);
    103 }
    104 
    105 TEST_P(Pkcs11X25519Test, ImportExportSpki) {
    106  DataBuffer exported;
    107  ScopedSECKEYPublicKey key = ImportPublicKey(GetParam().spki_);
    108 
    109  ScopedSECItem spki(SECKEY_EncodeDERSubjectPublicKeyInfo(key.get()));
    110  ASSERT_TRUE(spki);
    111  ASSERT_EQ(spki->len, GetParam().spki_.len());
    112  ASSERT_EQ(0, memcmp(spki->data, GetParam().spki_.data(), spki->len));
    113 }
    114 
    115 TEST_P(Pkcs11X25519Test, ImportConvertToPublicExport) {
    116  ScopedSECKEYPrivateKey privKey(ImportPrivateKey(GetParam().pkcs8_));
    117  ASSERT_TRUE(privKey);
    118 
    119  ScopedSECKEYPublicKey pubKey(SECKEY_ConvertToPublicKey(privKey.get()));
    120  ASSERT_TRUE(pubKey);
    121 
    122  ScopedSECItem der_spki(SECKEY_EncodeDERSubjectPublicKeyInfo(pubKey.get()));
    123  ASSERT_TRUE(der_spki);
    124  ASSERT_EQ(der_spki->len, GetParam().spki_.len());
    125  ASSERT_EQ(0, memcmp(der_spki->data, GetParam().spki_.data(), der_spki->len));
    126 }
    127 
    128 TEST_P(Pkcs11X25519Test, GenImportExport) {
    129  Pkcs11KeyPairGenerator generator(CKM_EC_MONTGOMERY_KEY_PAIR_GEN);
    130  ScopedSECKEYPrivateKey priv;
    131  ScopedSECKEYPublicKey pub;
    132 
    133  generator.GenerateKey(&priv, &pub, false);
    134  ASSERT_TRUE(priv);
    135  ASSERT_TRUE(pub);
    136 
    137  DataBuffer exportedPrivateKey, twiceExportedPrKey;
    138  ExportPrivateKey(&priv, exportedPrivateKey);
    139  ScopedSECKEYPrivateKey privExportedImported =
    140      ImportPrivateKey(exportedPrivateKey);
    141  ExportPrivateKey(&privExportedImported, twiceExportedPrKey);
    142  EXPECT_EQ(exportedPrivateKey, twiceExportedPrKey);
    143 
    144  ScopedSECItem spki(SECKEY_EncodeDERSubjectPublicKeyInfo(pub.get()));
    145  ASSERT_TRUE(spki);
    146 
    147  DataBuffer publicKeyDb(spki.get()->data, spki.get()->len);
    148  ScopedSECKEYPublicKey exportedImportedPublicKey =
    149      ImportPublicKey(publicKeyDb);
    150  ScopedSECItem spkiTwice(
    151      SECKEY_EncodeDERSubjectPublicKeyInfo(exportedImportedPublicKey.get()));
    152  ASSERT_TRUE(spkiTwice);
    153 
    154  ASSERT_EQ(spkiTwice->len, spki->len);
    155  ASSERT_EQ(0, memcmp(spki->data, spkiTwice->data, spki->len));
    156 }
    157 
    158 INSTANTIATE_TEST_SUITE_P(Pkcs11X25519Test, Pkcs11X25519Test,
    159                         ::testing::ValuesIn(kX25519Vectors));
    160 
    161 /*
    162    RFC 8410 describes several scenarios with the potential errors during
    163   exporting/encoding of the keys. See:
    164   https://www.rfc-editor.org/rfc/rfc8410#appendix-A. */
    165 
    166 /*
    167  PKCS8 (private) X25519 key explanation:
    168  NB: NSS does not currently support PKCS8 keys with the public key as an
    169  attribute.
    170 
    171  const uint8_t kX25519Pkcs8_1[] = {
    172    0x30, 0x2e, // where 0x2e is the length of the buffer
    173      0x02, 0x01, 0x00, // EC key version
    174        id-X25519    OBJECT IDENTIFIER ::= { 1 3 101 110 }
    175      0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, // algorithm identifier
    176      0x04, 0x22, // Outer octet string of length 0x22
    177      0x04, 0x20, // Inner octet string of length 0x20
    178 
    179    0xc8, 0x83, 0x8e, 0x76, 0xd0, 0x57, 0xdf, 0xb7, // Raw key
    180    0xd8, 0xc9, 0x5a, 0x69, 0xe1, 0x38, 0x16, 0x0a,
    181    0xdd, 0x63, 0x73, 0xfd, 0x71, 0xa4, 0xd2, 0x76,
    182    0xbb, 0x56, 0xe3, 0xa8, 0x1b, 0x64, 0xff, 0x61};
    183 
    184 */
    185 
    186 /* Private Key ASN.1 encoding errors */
    187 TEST_F(Pkcs11X25519Test, ImportPkcs8BitStringInsteadOfOctetString) {
    188  const uint8_t kX25519BitString[] = {
    189      0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e,
    190      0x04, 0x22, 0x03, 0x20, 0xc8, 0x83, 0x8e, 0x76, 0xd0, 0x57, 0xdf, 0xb7,
    191      0xd8, 0xc9, 0x5a, 0x69, 0xe1, 0x38, 0x16, 0x0a, 0xdd, 0x63, 0x73, 0xfd,
    192      0x71, 0xa4, 0xd2, 0x76, 0xbb, 0x56, 0xe3, 0xa8, 0x1b, 0x64, 0xff, 0x61};
    193 
    194  DataBuffer privateKeyPkcs8(
    195      DataBuffer(kX25519BitString, sizeof(kX25519BitString)));
    196  ScopedSECKEYPrivateKey key = ImportPrivateKey(privateKeyPkcs8);
    197  ASSERT_FALSE(key);
    198 }
    199 
    200 TEST_F(Pkcs11X25519Test, ImportPkcs8WrongLen) {
    201  /* The pkcs8 encoding has a wrong length (0x2d instead of 0x2e) */
    202  const uint8_t x25519_wrongLen[] = {
    203      0x30, 0x2d, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e,
    204      0x04, 0x22, 0x04, 0x20, 0xc8, 0x83, 0x8e, 0x76, 0xd0, 0x57, 0xdf, 0xb7,
    205      0xd8, 0xc9, 0x5a, 0x69, 0xe1, 0x38, 0x16, 0x0a, 0xdd, 0x63, 0x73, 0xfd,
    206      0x71, 0xa4, 0xd2, 0x76, 0xbb, 0x56, 0xe3, 0xa8, 0x1b, 0x64, 0xff, 0x61};
    207 
    208  DataBuffer privateKeyPkcs8(
    209      DataBuffer(x25519_wrongLen, sizeof(x25519_wrongLen)));
    210  ScopedSECKEYPrivateKey key = ImportPrivateKey(privateKeyPkcs8);
    211  ASSERT_FALSE(key);
    212 }
    213 
    214 /* Key encoding errors */
    215 TEST_F(Pkcs11X25519Test, ImportPkcs8NotSupportedOID) {
    216  /* The modified oid corresponds to not-supported x448:
    217    id-X448      OBJECT IDENTIFIER ::= { 1 3 101 111 }. */
    218  const uint8_t x25519_wrongOID[] = {
    219      0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6f,
    220      0x04, 0x22, 0x04, 0x20, 0xc8, 0x83, 0x8e, 0x76, 0xd0, 0x57, 0xdf, 0xb7,
    221      0xd8, 0xc9, 0x5a, 0x69, 0xe1, 0x38, 0x16, 0x0a, 0xdd, 0x63, 0x73, 0xfd,
    222      0x71, 0xa4, 0xd2, 0x76, 0xbb, 0x56, 0xe3, 0xa8, 0x1b, 0x64, 0xff, 0x61};
    223 
    224  DataBuffer privateKeyPkcs8(
    225      DataBuffer(x25519_wrongOID, sizeof(x25519_wrongOID)));
    226  ScopedSECKEYPrivateKey key = ImportPrivateKey(privateKeyPkcs8);
    227  ASSERT_FALSE(key);
    228 }
    229 
    230 TEST_F(Pkcs11X25519Test, ImportPkcs8ShortLenPrivateKey) {
    231  /* We change the length of the private key from 0x20 to 0x1f.
    232     Such way all the lengths will be decreased by one */
    233  const uint8_t x25519_shortPrivateKey[] = {
    234      0x30, 0x2d,  // the length is decreased by one
    235      0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04,
    236      0x21,        // the length is decreased by one
    237      0x04, 0x1f,  // the length is decreased by one
    238      0xc8, 0x83, 0x8e, 0x76, 0xd0, 0x57, 0xdf, 0xb7, 0xd8, 0xc9, 0x5a, 0x69,
    239      0xe1, 0x38, 0x16, 0x0a, 0xdd, 0x63, 0x73, 0xfd, 0x71, 0xa4, 0xd2, 0x76,
    240      // removed the last byte of the key
    241      0xbb, 0x56, 0xe3, 0xa8, 0x1b, 0x64, 0xff};
    242 
    243  DataBuffer privateKeyPkcs8(
    244      DataBuffer(x25519_shortPrivateKey, sizeof(x25519_shortPrivateKey)));
    245  ScopedSECKEYPrivateKey key = ImportPrivateKey(privateKeyPkcs8);
    246  ASSERT_TRUE(key);
    247 }
    248 
    249 /* We allow importing all-zero keys*/
    250 TEST_F(Pkcs11X25519Test, ImportPkcs8ZeroKey) {
    251  const uint8_t x25519_ZeroKey[] = {
    252      0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e,
    253      0x04, 0x22, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    254      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    255      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    256 
    257  DataBuffer privateKeyPkcs8(
    258      DataBuffer(x25519_ZeroKey, sizeof(x25519_ZeroKey)));
    259  ScopedSECKEYPrivateKey key = ImportPrivateKey(privateKeyPkcs8);
    260  ASSERT_TRUE(key);
    261 }
    262 
    263 TEST_P(Pkcs11X25519Test, KeyGeneration) {
    264  Pkcs11KeyPairGenerator generator(CKM_EC_MONTGOMERY_KEY_PAIR_GEN);
    265  ScopedSECKEYPrivateKey priv;
    266  ScopedSECKEYPublicKey pub;
    267 
    268  generator.GenerateKey(&priv, &pub, false);
    269  ASSERT_TRUE(priv);
    270  ASSERT_TRUE(pub);
    271 
    272  SECKEYPrivateKeyInfo* pkInfo = PK11_ExportPrivKeyInfo(priv.get(), nullptr);
    273  ASSERT_TRUE(pkInfo);
    274  /* 0x04 + len +  32 bytes the key */
    275  ASSERT_EQ(pkInfo->privateKey.len, (unsigned int)34);
    276  /* empty parameters for X25519*/
    277  ASSERT_EQ(pkInfo->algorithm.parameters.len, (unsigned int)0);
    278  ASSERT_TRUE(CheckAlgIsX25519(&pkInfo->algorithm.algorithm));
    279 
    280  ScopedCERTSubjectPublicKeyInfo spki(
    281      SECKEY_CreateSubjectPublicKeyInfo(pub.get()));
    282  ASSERT_TRUE(CheckAlgIsX25519(&spki->algorithm.algorithm));
    283  /* empty parameters for X25519*/
    284  ASSERT_EQ(spki->algorithm.parameters.len, (unsigned int)0);
    285 
    286  SECKEY_DestroyPrivateKeyInfo(pkInfo, PR_TRUE);
    287 }
    288 
    289 /* Public Key ASN.1 encoding errors */
    290 TEST_F(Pkcs11X25519Test, ImportExportSpkiWrongLen) {
    291  const uint8_t pk[] = {0x30, 0x2b, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e,
    292                        0x03, 0x21, 0x00, 0x1c, 0xf2, 0xb1, 0xe6, 0x02, 0x2e,
    293                        0xc5, 0x37, 0x37, 0x1e, 0xd7, 0xf5, 0x3e, 0x54, 0xfa,
    294                        0x11, 0x54, 0xd8, 0x3e, 0x98, 0xeb, 0x64, 0xea, 0x51,
    295                        0xfa, 0xe5, 0xb3, 0x30, 0x7c, 0xfe, 0x97, 0x06};
    296 
    297  DataBuffer publicKey(DataBuffer(pk, sizeof(pk)));
    298 
    299  ScopedSECKEYPublicKey key = ImportPublicKey(publicKey);
    300  ASSERT_FALSE(key);
    301 }
    302 
    303 /* Key encoding errors */
    304 TEST_F(Pkcs11X25519Test, ImportExportSpkiWrongOID) {
    305  /*0x2b, 0x65, 0x6d instead of 0x2b, 0x65, 0x6e */
    306  const uint8_t pk[] = {0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6d,
    307                        0x03, 0x21, 0x00, 0x1c, 0xf2, 0xb1, 0xe6, 0x02, 0x2e,
    308                        0xc5, 0x37, 0x37, 0x1e, 0xd7, 0xf5, 0x3e, 0x54, 0xfa,
    309                        0x11, 0x54, 0xd8, 0x3e, 0x98, 0xeb, 0x64, 0xea, 0x51,
    310                        0xfa, 0xe5, 0xb3, 0x30, 0x7c, 0xfe, 0x97, 0x06};
    311 
    312  DataBuffer publicKey(DataBuffer(pk, sizeof(pk)));
    313  ScopedSECKEYPublicKey key = ImportPublicKey(publicKey);
    314  ASSERT_FALSE(key);
    315 }
    316 
    317 /* Key encoding errors */
    318 TEST_F(Pkcs11X25519Test, ImportExportSpkiWrongKeyID) {
    319  /*0x2b, 0x65, 0x6d instead of 0x2b, 0x65, 0x6e */
    320  const uint8_t pk[] = {0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6d,
    321                        0x04,  // 0x04 instead of 0x03
    322                        0x21, 0x00, 0x1c, 0xf2, 0xb1, 0xe6, 0x02, 0x2e, 0xc5,
    323                        0x37, 0x37, 0x1e, 0xd7, 0xf5, 0x3e, 0x54, 0xfa, 0x11,
    324                        0x54, 0xd8, 0x3e, 0x98, 0xeb, 0x64, 0xea, 0x51, 0xfa,
    325                        0xe5, 0xb3, 0x30, 0x7c, 0xfe, 0x97, 0x06};
    326 
    327  DataBuffer publicKey(DataBuffer(pk, sizeof(pk)));
    328  ScopedSECKEYPublicKey key = ImportPublicKey(publicKey);
    329  ASSERT_FALSE(key);
    330 }
    331 
    332 /* We allow to import all-zero keys. */
    333 TEST_F(Pkcs11X25519Test, ImportExportSpkiZeroKey) {
    334  const uint8_t pk[] = {0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e,
    335                        0x03, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    336                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    337                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    338                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    339 
    340  DataBuffer publicKey(DataBuffer(pk, sizeof(pk)));
    341  ScopedSECKEYPublicKey key = ImportPublicKey(publicKey);
    342  ASSERT_TRUE(key);
    343 }
    344 
    345 }  // namespace nss_test