Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Bug 554827 - Support additional pseudorandom functions for PKCS #5 PB…
…KDF2, r=mt,wtc

--HG--
extra : histedit_source : 2b558c96d244350d08784459ce007d94d7447f1f%2C247b42f07d1f34d1568a89f1919018f9f7b9ce8c
  • Loading branch information
martinthomson committed Nov 13, 2015
1 parent 1d9a24f commit a1c91e9
Show file tree
Hide file tree
Showing 10 changed files with 183 additions and 51 deletions.
24 changes: 16 additions & 8 deletions external_tests/common/scoped_ptrs.h
Expand Up @@ -7,28 +7,36 @@
#ifndef scoped_ptrs_h__
#define scoped_ptrs_h__

#include "keyhi.h"

namespace nss_test {

void ScopedDelete(PK11SlotInfo* slot) { PK11_FreeSlot(slot); }
void ScopedDelete(SECItem* item) { SECITEM_FreeItem(item, true); }
void ScopedDelete(SECKEYPublicKey* key) { SECKEY_DestroyPublicKey(key); }
void ScopedDelete(SECKEYPrivateKey* key) { SECKEY_DestroyPrivateKey(key); }
void ScopedDelete(CERTSubjectPublicKeyInfo* spki) {
SECKEY_DestroySubjectPublicKeyInfo(spki);
}
struct ScopedDelete {
void operator()(PK11SlotInfo* slot) { PK11_FreeSlot(slot); }
void operator()(SECItem* item) { SECITEM_FreeItem(item, true); }
void operator()(PK11SymKey* key) { PK11_FreeSymKey(key); }
void operator()(SECKEYPublicKey* key) { SECKEY_DestroyPublicKey(key); }
void operator()(SECKEYPrivateKey* key) { SECKEY_DestroyPrivateKey(key); }
void operator()(SECAlgorithmID* id) { SECOID_DestroyAlgorithmID(id, true); }
void operator()(CERTSubjectPublicKeyInfo* spki) {
SECKEY_DestroySubjectPublicKeyInfo(spki);
}
};

template<class T>
struct ScopedMaybeDelete {
void operator()(T* ptr) { if (ptr) ScopedDelete(ptr); }
void operator()(T* ptr) { if (ptr) { ScopedDelete del; del(ptr); } }
};

template<class T>
using ScopedUniquePtr = std::unique_ptr<T, ScopedMaybeDelete<T>>;

using ScopedPK11SlotInfo = ScopedUniquePtr<PK11SlotInfo>;
using ScopedSECItem = ScopedUniquePtr<SECItem>;
using ScopedPK11SymKey = ScopedUniquePtr<PK11SymKey>;
using ScopedSECKEYPublicKey = ScopedUniquePtr<SECKEYPublicKey>;
using ScopedSECKEYPrivateKey = ScopedUniquePtr<SECKEYPrivateKey>;
using ScopedSECAlgorithmID = ScopedUniquePtr<SECAlgorithmID>;
using ScopedCERTSubjectPublicKeyInfo = ScopedUniquePtr<CERTSubjectPublicKeyInfo>;

} // namespace nss_test
Expand Down
1 change: 1 addition & 0 deletions external_tests/pk11_gtest/manifest.mn
Expand Up @@ -7,6 +7,7 @@ DEPTH = ../..
MODULE = nss

CPPSRCS = \
pk11_pbkdf2_unittest.cc \
pk11_rsapss_unittest.cc \
pk11_gtest.cc \
$(NULL)
Expand Down
100 changes: 100 additions & 0 deletions external_tests/pk11_gtest/pk11_pbkdf2_unittest.cc
@@ -0,0 +1,100 @@
/* -*- 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 "nss.h"
#include "pk11pub.h"
#include <memory>

#include "gtest/gtest.h"
#include "scoped_ptrs.h"

namespace nss_test {

static unsigned char* ToUcharPtr(std::string& str) {
return const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(str.c_str()));
}

class Pkcs11Pbkdf2Test : public ::testing::Test {
public:
void Derive(std::vector<uint8_t>& derived, SECOidTag hash_alg)
{
// Shared between test vectors.
const unsigned int iterations = 4096;
std::string pass("passwordPASSWORDpassword");
std::string salt("saltSALTsaltSALTsaltSALTsaltSALTsalt");

// Derivation must succeed with the right values.
EXPECT_TRUE(DeriveBytes(pass, salt, derived, hash_alg, iterations));

// Derivation must fail when the password is bogus.
std::string bogusPass("PasswordPASSWORDpassword");
EXPECT_FALSE(DeriveBytes(bogusPass, salt, derived, hash_alg, iterations));

// Derivation must fail when the salt is bogus.
std::string bogusSalt("SaltSALTsaltSALTsaltSALTsaltSALTsalt");
EXPECT_FALSE(DeriveBytes(pass, bogusSalt, derived, hash_alg, iterations));

// Derivation must fail when using the wrong hash function.
SECOidTag next_hash_alg = static_cast<SECOidTag>(hash_alg + 1);
EXPECT_FALSE(DeriveBytes(pass, salt, derived, next_hash_alg, iterations));

// Derivation must fail when using the wrong number of iterations.
EXPECT_FALSE(DeriveBytes(pass, salt, derived, hash_alg, iterations + 1));
}

private:
bool DeriveBytes(std::string& pass, std::string& salt,
std::vector<uint8_t>& derived, SECOidTag hash_alg,
unsigned int iterations)
{
SECItem passItem = { siBuffer, ToUcharPtr(pass),
static_cast<unsigned int>(pass.length()) };
SECItem saltItem = { siBuffer, ToUcharPtr(salt),
static_cast<unsigned int>(salt.length()) };

// Set up PBKDF2 params.
ScopedSECAlgorithmID alg_id(
PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2, hash_alg, hash_alg,
derived.size(), iterations, &saltItem));

// Derive.
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ScopedPK11SymKey symKey(
PK11_PBEKeyGen(slot.get(), alg_id.get(), &passItem, false, nullptr));

SECStatus rv = PK11_ExtractKeyValue(symKey.get());
EXPECT_EQ(rv, SECSuccess);

SECItem* keyData = PK11_GetKeyData(symKey.get());
return !memcmp(&derived[0], keyData->data, keyData->len);
}
};

// RFC 6070 <http://tools.ietf.org/html/rfc6070>
TEST_F(Pkcs11Pbkdf2Test, DeriveKnown1) {
std::vector<uint8_t> derived = {
0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b, 0x80, 0xc8, 0xd8, 0x36,
0x62, 0xc0, 0xe4, 0x4a, 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70, 0x38
};

Derive(derived, SEC_OID_HMAC_SHA1);
}

// https://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors
TEST_F(Pkcs11Pbkdf2Test, DeriveKnown2) {
std::vector<uint8_t> derived = {
0x34, 0x8c, 0x89, 0xdb, 0xcb, 0xd3, 0x2b, 0x2f, 0x32, 0xd8, 0x14, 0xb8,
0x11, 0x6e, 0x84, 0xcf, 0x2b, 0x17, 0x34, 0x7e, 0xbc, 0x18, 0x00, 0x18,
0x1c, 0x4e, 0x2a, 0x1f, 0xb8, 0xdd, 0x53, 0xe1, 0xc6, 0x35, 0x51, 0x8c,
0x7d, 0xac, 0x47, 0xe9
};

Derive(derived, SEC_OID_HMAC_SHA256);
}

} // namespace nss_test

1 change: 0 additions & 1 deletion external_tests/pk11_gtest/pk11_rsapss_unittest.cc
Expand Up @@ -5,7 +5,6 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "nss.h"
#include "keyhi.h"
#include "pk11pub.h"
#include "sechash.h"
#include <memory>
Expand Down
29 changes: 21 additions & 8 deletions lib/pk11wrap/pk11pbe.c
Expand Up @@ -636,7 +636,7 @@ sec_pkcs5CreateAlgorithmID(SECOidTag algorithm,
goto loser;
}
}
/* currently only SEC_OID_HMAC_SHA1 is defined */
/* currently SEC_OID_HMAC_SHA1 is the default */
if (prfAlg == SEC_OID_UNKNOWN) {
prfAlg = SEC_OID_HMAC_SHA1;
}
Expand Down Expand Up @@ -805,13 +805,26 @@ pbe_PK11AlgidToParam(SECAlgorithmID *algid,SECItem *mech)
p5_param.pPrfAlgId->algorithm.data != 0) {
prfAlgTag = SECOID_GetAlgorithmTag(p5_param.pPrfAlgId);
}
if (prfAlgTag == SEC_OID_HMAC_SHA1) {
pbeV2_params->prf = CKP_PKCS5_PBKD2_HMAC_SHA1;
} else {
/* only SHA1_HMAC is currently supported by PKCS #11 */
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
goto loser;
}
switch (prfAlgTag) {
case SEC_OID_HMAC_SHA1:
pbeV2_params->prf = CKP_PKCS5_PBKD2_HMAC_SHA1;
break;
case SEC_OID_HMAC_SHA224:
pbeV2_params->prf = CKP_PKCS5_PBKD2_HMAC_SHA224;
break;
case SEC_OID_HMAC_SHA256:
pbeV2_params->prf = CKP_PKCS5_PBKD2_HMAC_SHA256;
break;
case SEC_OID_HMAC_SHA384:
pbeV2_params->prf = CKP_PKCS5_PBKD2_HMAC_SHA384;
break;
case SEC_OID_HMAC_SHA512:
pbeV2_params->prf = CKP_PKCS5_PBKD2_HMAC_SHA512;
break;
default:
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
goto loser;
}

/* probably should fetch these from the prfAlgid */
pbeV2_params->pPrfData = NULL;
Expand Down
26 changes: 7 additions & 19 deletions lib/softoken/lowpbe.c
Expand Up @@ -53,9 +53,7 @@ struct nsspkcs5V2PBEParameterStr {
};

typedef struct nsspkcs5V2PBEParameterStr nsspkcs5V2PBEParameter;
#define PBKDF2

#ifdef PBKDF2
static const SEC_ASN1Template NSSPKCS5V2PBES2ParameterTemplate[] =
{
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(nsspkcs5V2PBEParameter) },
Expand All @@ -81,7 +79,6 @@ static const SEC_ASN1Template NSSPKCS5V2PBEParameterTemplate[] =
SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
{ 0 }
};
#endif

SECStatus
nsspkcs5_HashBuf(const SECHashObject *hashObj, unsigned char *dest,
Expand Down Expand Up @@ -301,8 +298,6 @@ nsspkcs5_PBKDF1Extended(const SECHashObject *hashObj,
return newHash;
}

#ifdef PBKDF2

/*
* PBDKDF2 is PKCS #5 v2.0 it's currently not used by NSS
*/
Expand Down Expand Up @@ -413,7 +408,6 @@ nsspkcs5_PBKDF2(const SECHashObject *hashobj, NSSPKCS5PBEParameter *pbe_param,

return result;
}
#endif

#define HMAC_BUFFER 64
#define NSSPBE_ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y))
Expand Down Expand Up @@ -600,14 +594,12 @@ nsspkcs5_ComputeKeyAndIV(NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem,
}

break;
#ifdef PBKDF2
case NSSPKCS5_PBKDF2:
hash = nsspkcs5_PBKDF2(hashObj,pbe_param,pwitem);
if (getIV) {
PORT_Memcpy(iv->data, pbe_param->ivData, iv->len);
}
break;
#endif
case NSSPKCS5_PKCS12_V2:
if (getIV) {
hash = nsspkcs5_PKCS12PBE(hashObj,pbe_param,pwitem,
Expand Down Expand Up @@ -651,13 +643,14 @@ nsspkcs5_ComputeKeyAndIV(NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem,
}

static SECStatus
nsspkcs5_FillInParam(SECOidTag algorithm, NSSPKCS5PBEParameter *pbe_param)
nsspkcs5_FillInParam(SECOidTag algorithm, HASH_HashType hashType,
NSSPKCS5PBEParameter *pbe_param)
{
PRBool skipType = PR_FALSE;

pbe_param->keyLen = 5;
pbe_param->ivLen = 8;
pbe_param->hashType = HASH_AlgSHA1;
pbe_param->hashType = hashType;
pbe_param->pbeType = NSSPKCS5_PBKDF1;
pbe_param->encAlg = SEC_OID_RC2_CBC;
pbe_param->is2KeyDES = PR_FALSE;
Expand Down Expand Up @@ -717,7 +710,6 @@ nsspkcs5_FillInParam(SECOidTag algorithm, NSSPKCS5PBEParameter *pbe_param)
pbe_param->encAlg = SEC_OID_RC4;
break;

#ifdef PBKDF2
case SEC_OID_PKCS5_PBKDF2:
case SEC_OID_PKCS5_PBES2:
case SEC_OID_PKCS5_PBMAC1:
Expand All @@ -727,7 +719,6 @@ nsspkcs5_FillInParam(SECOidTag algorithm, NSSPKCS5PBEParameter *pbe_param)
pbe_param->encAlg = SEC_OID_PKCS5_PBKDF2;
pbe_param->keyLen = 0; /* needs to be set by caller after return */
break;
#endif

default:
return SECFailure;
Expand All @@ -739,7 +730,8 @@ nsspkcs5_FillInParam(SECOidTag algorithm, NSSPKCS5PBEParameter *pbe_param)
/* decode the algid and generate a PKCS 5 parameter from it
*/
NSSPKCS5PBEParameter *
nsspkcs5_NewParam(SECOidTag alg, SECItem *salt, int iterator)
nsspkcs5_NewParam(SECOidTag alg, HASH_HashType hashType, SECItem *salt,
int iterator)
{
PLArenaPool *arena = NULL;
NSSPKCS5PBEParameter *pbe_param = NULL;
Expand All @@ -759,7 +751,7 @@ nsspkcs5_NewParam(SECOidTag alg, SECItem *salt, int iterator)

pbe_param->poolp = arena;

rv = nsspkcs5_FillInParam(alg, pbe_param);
rv = nsspkcs5_FillInParam(alg, hashType, pbe_param);
if (rv != SECSuccess) {
goto loser;
}
Expand Down Expand Up @@ -823,7 +815,7 @@ nsspkcs5_AlgidToParam(SECAlgorithmID *algid)
goto loser;
}

pbe_param = nsspkcs5_NewParam(algorithm, NULL, 1);
pbe_param = nsspkcs5_NewParam(algorithm, HASH_AlgSHA1, NULL, 1);
if (pbe_param == NULL) {
goto loser;
}
Expand All @@ -839,7 +831,6 @@ nsspkcs5_AlgidToParam(SECAlgorithmID *algid)
rv = SEC_ASN1DecodeItem(pbe_param->poolp, pbe_param,
NSSPKCS5PKCS12V2PBEParameterTemplate, &algid->parameters);
break;
#ifdef PBKDF2
case NSSPKCS5_PBKDF2:
PORT_Memset(&pbev2_param,0, sizeof(pbev2_param));
/* just the PBE */
Expand Down Expand Up @@ -874,7 +865,6 @@ nsspkcs5_AlgidToParam(SECAlgorithmID *algid)
rv = SECFailure;
}
break;
#endif
}

loser:
Expand Down Expand Up @@ -1316,7 +1306,6 @@ nsspkcs5_CreateAlgorithmID(PLArenaPool *arena, SECOidTag algorithm,
dummy = SEC_ASN1EncodeItem(arena, &der_param, pbe_param,
NSSPKCS5PKCS12V2PBEParameterTemplate);
break;
#ifdef PBKDF2
case NSSPKCS5_PBKDF2:
if (pbe_param->keyLength.data == NULL) {
dummy = SEC_ASN1EncodeInteger(pbe_param->poolp,
Expand Down Expand Up @@ -1347,7 +1336,6 @@ nsspkcs5_CreateAlgorithmID(PLArenaPool *arena, SECOidTag algorithm,
dummy = SEC_ASN1EncodeItem(arena, &der_param, &pkcs5v2_param,
NSSPKCS5V2PBES2ParameterTemplate);
break;
#endif
default:
break;
}
Expand Down
3 changes: 2 additions & 1 deletion lib/softoken/lowpbe.h
Expand Up @@ -77,7 +77,8 @@ nsspkcs5_AlgidToParam(SECAlgorithmID *algid);
* keyDB which only support PKCS 5 v1, PFX, and PKCS 12.
*/
NSSPKCS5PBEParameter *
nsspkcs5_NewParam(SECOidTag alg, SECItem *salt, int iterator);
nsspkcs5_NewParam(SECOidTag alg, HASH_HashType hashType, SECItem *salt,
int iterator);


/* Encrypt/Decrypt data using password based encryption.
Expand Down

0 comments on commit a1c91e9

Please sign in to comment.