Bug 1034851 - Add wrapKey and unwrapKey methods to WebCrypto API r=bz

This commit is contained in:
Richard Barnes 2014-07-19 08:24:00 -05:00
Родитель e3578f6893
Коммит 58860abf23
9 изменённых файлов: 541 добавлений и 61 удалений

Просмотреть файл

@ -42,7 +42,7 @@ SubtleCrypto::WrapObject(JSContext* aCx)
if (aRv.Failed()) { \
return nullptr; \
} \
nsRefPtr<WebCryptoTask> task = WebCryptoTask::Operation ## Task(__VA_ARGS__); \
nsRefPtr<WebCryptoTask> task = WebCryptoTask::Create ## Operation ## Task(__VA_ARGS__); \
task->DispatchWithPromise(p); \
return p.forget();
@ -148,5 +148,32 @@ SubtleCrypto::DeriveBits(JSContext* cx,
SUBTLECRYPTO_METHOD_BODY(DeriveBits, aRv, cx, algorithm, baseKey, length)
}
already_AddRefed<Promise>
SubtleCrypto::WrapKey(JSContext* cx,
const nsAString& format,
CryptoKey& key,
CryptoKey& wrappingKey,
const ObjectOrString& wrapAlgorithm,
ErrorResult& aRv)
{
SUBTLECRYPTO_METHOD_BODY(WrapKey, aRv, cx, format, key, wrappingKey, wrapAlgorithm)
}
already_AddRefed<Promise>
SubtleCrypto::UnwrapKey(JSContext* cx,
const nsAString& format,
const ArrayBufferViewOrArrayBuffer& wrappedKey,
CryptoKey& unwrappingKey,
const ObjectOrString& unwrapAlgorithm,
const ObjectOrString& unwrappedKeyAlgorithm,
bool extractable,
const Sequence<nsString>& keyUsages,
ErrorResult& aRv)
{
SUBTLECRYPTO_METHOD_BODY(UnwrapKey, aRv, cx, format, wrappedKey, unwrappingKey,
unwrapAlgorithm, unwrappedKeyAlgorithm,
extractable, keyUsages)
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -102,6 +102,23 @@ public:
uint32_t length,
ErrorResult& aRv);
already_AddRefed<Promise> WrapKey(JSContext* cx,
const nsAString& format,
CryptoKey& key,
CryptoKey& wrappingKey,
const ObjectOrString& wrapAlgorithm,
ErrorResult& aRv);
already_AddRefed<Promise> UnwrapKey(JSContext* cx,
const nsAString& format,
const ArrayBufferViewOrArrayBuffer& wrappedKey,
CryptoKey& unwrappingKey,
const ObjectOrString& unwrapAlgorithm,
const ObjectOrString& unwrappedKeyAlgorithm,
bool extractable,
const Sequence<nsString>& keyUsages,
ErrorResult& aRv);
private:
nsCOMPtr<nsPIDOMWindow> mWindow;
};

Просмотреть файл

@ -10,6 +10,14 @@
namespace mozilla {
namespace dom {
uint8_t*
CryptoBuffer::Assign(const CryptoBuffer& aData)
{
// Same as in nsTArray_Impl::operator=, but return the value
// returned from ReplaceElementsAt to enable OOM detection
return ReplaceElementsAt(0, Length(), aData.Elements(), aData.Length());
}
uint8_t*
CryptoBuffer::Assign(const uint8_t* aData, uint32_t aLength)
{

Просмотреть файл

@ -20,6 +20,7 @@ class OwningArrayBufferViewOrArrayBuffer;
class CryptoBuffer : public FallibleTArray<uint8_t>
{
public:
uint8_t* Assign(const CryptoBuffer& aData);
uint8_t* Assign(const uint8_t* aData, uint32_t aLength);
uint8_t* Assign(const SECItem* aItem);
uint8_t* Assign(const ArrayBuffer& aData);

Просмотреть файл

@ -299,17 +299,48 @@ private:
}
};
class AesTask : public ReturnArrayBufferViewTask
class DeferredData
{
public:
template<class T>
void SetData(const T& aData) {
mDataIsSet = mData.Assign(aData);
}
protected:
DeferredData()
: mDataIsSet(false)
{}
CryptoBuffer mData;
bool mDataIsSet;
};
class AesTask : public ReturnArrayBufferViewTask,
public DeferredData
{
public:
AesTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
CryptoKey& aKey, bool aEncrypt)
: mSymKey(aKey.GetSymKey())
, mEncrypt(aEncrypt)
{
Init(aCx, aAlgorithm, aKey, aEncrypt);
}
AesTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
CryptoKey& aKey, const CryptoOperationData& aData,
bool aEncrypt)
: mSymKey(aKey.GetSymKey())
, mEncrypt(aEncrypt)
{
ATTEMPT_BUFFER_INIT(mData, aData);
Init(aCx, aAlgorithm, aKey, aEncrypt);
SetData(aData);
}
void Init(JSContext* aCx, const ObjectOrString& aAlgorithm,
CryptoKey& aKey, bool aEncrypt)
{
nsString algName;
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
if (NS_FAILED(mEarlyRv)) {
@ -398,7 +429,6 @@ private:
CK_MECHANISM_TYPE mMechanism;
CryptoBuffer mSymKey;
CryptoBuffer mIv; // Initialization vector
CryptoBuffer mData;
CryptoBuffer mAad; // Additional Authenticated Data
uint8_t mTagLength;
uint8_t mCounterLength;
@ -408,6 +438,10 @@ private:
{
nsresult rv;
if (!mDataIsSet) {
return NS_ERROR_DOM_OPERATION_ERR;
}
// Construct the parameters object depending on algorithm
SECItem param;
ScopedSECItem cbcParam;
@ -476,9 +510,19 @@ private:
}
};
class RsaesPkcs1Task : public ReturnArrayBufferViewTask
class RsaesPkcs1Task : public ReturnArrayBufferViewTask,
public DeferredData
{
public:
RsaesPkcs1Task(JSContext* aCx, const ObjectOrString& aAlgorithm,
CryptoKey& aKey, bool aEncrypt)
: mPrivKey(aKey.GetPrivateKey())
, mPubKey(aKey.GetPublicKey())
, mEncrypt(aEncrypt)
{
Init(aCx, aAlgorithm, aKey, aEncrypt);
}
RsaesPkcs1Task(JSContext* aCx, const ObjectOrString& aAlgorithm,
CryptoKey& aKey, const CryptoOperationData& aData,
bool aEncrypt)
@ -486,9 +530,15 @@ public:
, mPubKey(aKey.GetPublicKey())
, mEncrypt(aEncrypt)
{
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSAES_PKCS1);
Init(aCx, aAlgorithm, aKey, aEncrypt);
SetData(aData);
}
ATTEMPT_BUFFER_INIT(mData, aData);
void Init(JSContext* aCx, const ObjectOrString& aAlgorithm,
CryptoKey& aKey, bool aEncrypt)
{
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSAES_PKCS1);
if (mEncrypt) {
if (!mPubKey) {
@ -496,14 +546,6 @@ public:
return;
}
mStrength = SECKEY_PublicKeyStrength(mPubKey);
// Verify that the data input is not too big
// (as required by PKCS#1 / RFC 3447, Section 7.2)
// http://tools.ietf.org/html/rfc3447#section-7.2
if (mData.Length() > mStrength - 11) {
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
return;
}
} else {
if (!mPrivKey) {
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
@ -516,10 +558,25 @@ public:
private:
ScopedSECKEYPrivateKey mPrivKey;
ScopedSECKEYPublicKey mPubKey;
CryptoBuffer mData;
uint32_t mStrength;
bool mEncrypt;
virtual nsresult BeforeCrypto() MOZ_OVERRIDE
{
if (!mDataIsSet) {
return NS_ERROR_DOM_OPERATION_ERR;
}
// Verify that the data input is not too big
// (as required by PKCS#1 / RFC 3447, Section 7.2)
// http://tools.ietf.org/html/rfc3447#section-7.2
if (mEncrypt && mData.Length() > mStrength - 11) {
return NS_ERROR_DOM_DATA_ERR;
}
return NS_OK;
}
virtual nsresult DoCrypto() MOZ_OVERRIDE
{
nsresult rv;
@ -549,9 +606,19 @@ private:
}
};
class RsaOaepTask : public ReturnArrayBufferViewTask
class RsaOaepTask : public ReturnArrayBufferViewTask,
public DeferredData
{
public:
RsaOaepTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
CryptoKey& aKey, bool aEncrypt)
: mPrivKey(aKey.GetPrivateKey())
, mPubKey(aKey.GetPublicKey())
, mEncrypt(aEncrypt)
{
Init(aCx, aAlgorithm, aKey, aEncrypt);
}
RsaOaepTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
CryptoKey& aKey, const CryptoOperationData& aData,
bool aEncrypt)
@ -559,9 +626,14 @@ public:
, mPubKey(aKey.GetPublicKey())
, mEncrypt(aEncrypt)
{
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSA_OAEP);
Init(aCx, aAlgorithm, aKey, aEncrypt);
SetData(aData);
}
ATTEMPT_BUFFER_INIT(mData, aData);
void Init(JSContext* aCx, const ObjectOrString& aAlgorithm,
CryptoKey& aKey, bool aEncrypt)
{
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSA_OAEP);
if (mEncrypt) {
if (!mPubKey) {
@ -620,7 +692,6 @@ private:
ScopedSECKEYPrivateKey mPrivKey;
ScopedSECKEYPublicKey mPubKey;
CryptoBuffer mLabel;
CryptoBuffer mData;
uint32_t mStrength;
bool mEncrypt;
@ -628,6 +699,10 @@ private:
{
nsresult rv;
if (!mDataIsSet) {
return NS_ERROR_DOM_OPERATION_ERR;
}
// Ciphertext is an integer mod the modulus, so it will be
// no longer than mStrength octets
if (!mResult.SetLength(mStrength)) {
@ -895,10 +970,10 @@ private:
}
};
class SimpleDigestTask : public ReturnArrayBufferViewTask
class DigestTask : public ReturnArrayBufferViewTask
{
public:
SimpleDigestTask(JSContext* aCx,
DigestTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
const CryptoOperationData& aData)
{
@ -987,7 +1062,14 @@ public:
}
}
void SetKeyData(const CryptoBuffer& aKeyData)
{
// An OOM will just result in an error in BeforeCrypto
mKeyData = aKeyData;
}
protected:
CryptoBuffer mKeyData;
nsRefPtr<CryptoKey> mKey;
nsString mAlgName;
@ -1069,7 +1151,8 @@ public:
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
if (mKey->HasUsageOtherThan(CryptoKey::ENCRYPT | CryptoKey::DECRYPT)) {
if (mKey->HasUsageOtherThan(CryptoKey::ENCRYPT | CryptoKey::DECRYPT |
CryptoKey::WRAPKEY | CryptoKey::UNWRAPKEY)) {
return NS_ERROR_DOM_DATA_ERR;
}
@ -1102,14 +1185,7 @@ public:
return NS_OK;
}
void SetKeyData(const CryptoBuffer& aKeyData)
{
// An OOM will just result in an error in BeforeCrypto
mKeyData = aKeyData;
}
private:
CryptoBuffer mKeyData;
nsString mHashName;
};
@ -1158,7 +1234,6 @@ public:
}
private:
CryptoBuffer mKeyData;
nsString mFormat;
nsString mHashName;
uint32_t mModulusLength;
@ -1215,9 +1290,9 @@ private:
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1) ||
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
if ((mKey->GetKeyType() == CryptoKey::PUBLIC &&
mKey->HasUsageOtherThan(CryptoKey::ENCRYPT)) ||
mKey->HasUsageOtherThan(CryptoKey::ENCRYPT | CryptoKey::WRAPKEY)) ||
(mKey->GetKeyType() == CryptoKey::PRIVATE &&
mKey->HasUsageOtherThan(CryptoKey::DECRYPT))) {
mKey->HasUsageOtherThan(CryptoKey::DECRYPT | CryptoKey::UNWRAPKEY))) {
return NS_ERROR_DOM_DATA_ERR;
}
} else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
@ -1252,10 +1327,10 @@ private:
};
class UnifiedExportKeyTask : public ReturnArrayBufferViewTask
class ExportKeyTask : public ReturnArrayBufferViewTask
{
public:
UnifiedExportKeyTask(const nsAString& aFormat, CryptoKey& aKey)
ExportKeyTask(const nsAString& aFormat, CryptoKey& aKey)
: mFormat(aFormat)
, mSymKey(aKey.GetSymKey())
, mPrivateKey(aKey.GetPrivateKey())
@ -1779,11 +1854,69 @@ private:
}
};
template<class KeyEncryptTask>
class WrapKeyTask : public ExportKeyTask
{
public:
WrapKeyTask(JSContext* aCx,
const nsAString& aFormat,
CryptoKey& aKey,
CryptoKey& aWrappingKey,
const ObjectOrString& aWrapAlgorithm)
: ExportKeyTask(aFormat, aKey)
{
if (NS_FAILED(mEarlyRv)) {
return;
}
mTask = new KeyEncryptTask(aCx, aWrapAlgorithm, aWrappingKey, true);
}
private:
nsRefPtr<KeyEncryptTask> mTask;
virtual void Resolve() MOZ_OVERRIDE {
mTask->SetData(mResult);
mTask->DispatchWithPromise(mResultPromise);
}
virtual void Cleanup() MOZ_OVERRIDE
{
mTask = nullptr;
}
};
template<class KeyEncryptTask>
class UnwrapKeyTask : public KeyEncryptTask
{
public:
UnwrapKeyTask(JSContext* aCx,
const ArrayBufferViewOrArrayBuffer& aWrappedKey,
CryptoKey& aUnwrappingKey,
const ObjectOrString& aUnwrapAlgorithm,
ImportKeyTask* aTask)
: KeyEncryptTask(aCx, aUnwrapAlgorithm, aUnwrappingKey, aWrappedKey, false)
, mTask(aTask)
{}
private:
nsRefPtr<ImportKeyTask> mTask;
virtual void Resolve() MOZ_OVERRIDE {
mTask->SetKeyData(KeyEncryptTask::mResult);
mTask->DispatchWithPromise(KeyEncryptTask::mResultPromise);
}
virtual void Cleanup() MOZ_OVERRIDE
{
mTask = nullptr;
}
};
// Task creation methods for WebCryptoTask
WebCryptoTask*
WebCryptoTask::EncryptDecryptTask(JSContext* aCx,
WebCryptoTask::CreateEncryptDecryptTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
CryptoKey& aKey,
const CryptoOperationData& aData,
@ -1819,7 +1952,7 @@ WebCryptoTask::EncryptDecryptTask(JSContext* aCx,
}
WebCryptoTask*
WebCryptoTask::SignVerifyTask(JSContext* aCx,
WebCryptoTask::CreateSignVerifyTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
CryptoKey& aKey,
const CryptoOperationData& aSignature,
@ -1852,16 +1985,16 @@ WebCryptoTask::SignVerifyTask(JSContext* aCx,
}
WebCryptoTask*
WebCryptoTask::DigestTask(JSContext* aCx,
WebCryptoTask::CreateDigestTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
const CryptoOperationData& aData)
{
Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_DIGEST);
return new SimpleDigestTask(aCx, aAlgorithm, aData);
return new DigestTask(aCx, aAlgorithm, aData);
}
WebCryptoTask*
WebCryptoTask::ImportKeyTask(JSContext* aCx,
WebCryptoTask::CreateImportKeyTask(JSContext* aCx,
const nsAString& aFormat,
const KeyData& aKeyData,
const ObjectOrString& aAlgorithm,
@ -1895,7 +2028,7 @@ WebCryptoTask::ImportKeyTask(JSContext* aCx,
}
WebCryptoTask*
WebCryptoTask::ExportKeyTask(const nsAString& aFormat,
WebCryptoTask::CreateExportKeyTask(const nsAString& aFormat,
CryptoKey& aKey)
{
Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_EXPORTKEY);
@ -1903,12 +2036,12 @@ WebCryptoTask::ExportKeyTask(const nsAString& aFormat,
if (aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
} else {
return new UnifiedExportKeyTask(aFormat, aKey);
return new ExportKeyTask(aFormat, aKey);
}
}
WebCryptoTask*
WebCryptoTask::GenerateKeyTask(JSContext* aCx,
WebCryptoTask::CreateGenerateKeyTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
bool aExtractable,
const Sequence<nsString>& aKeyUsages)
@ -1937,7 +2070,7 @@ WebCryptoTask::GenerateKeyTask(JSContext* aCx,
}
WebCryptoTask*
WebCryptoTask::DeriveKeyTask(JSContext* aCx,
WebCryptoTask::CreateDeriveKeyTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
CryptoKey& aBaseKey,
const ObjectOrString& aDerivedKeyType,
@ -1961,7 +2094,7 @@ WebCryptoTask::DeriveKeyTask(JSContext* aCx,
}
WebCryptoTask*
WebCryptoTask::DeriveBitsTask(JSContext* aCx,
WebCryptoTask::CreateDeriveBitsTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
CryptoKey& aKey,
uint32_t aLength)
@ -1981,6 +2114,108 @@ WebCryptoTask::DeriveBitsTask(JSContext* aCx,
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
}
WebCryptoTask*
WebCryptoTask::CreateWrapKeyTask(JSContext* aCx,
const nsAString& aFormat,
CryptoKey& aKey,
CryptoKey& aWrappingKey,
const ObjectOrString& aWrapAlgorithm)
{
Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_WRAPKEY);
// Ensure key is usable for this operation
if (!aWrappingKey.HasUsage(CryptoKey::WRAPKEY)) {
return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR);
}
nsString wrapAlgName;
nsresult rv = GetAlgorithmName(aCx, aWrapAlgorithm, wrapAlgName);
if (NS_FAILED(rv)) {
return new FailureTask(rv);
}
if (wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
return new WrapKeyTask<AesTask>(aCx, aFormat, aKey,
aWrappingKey, aWrapAlgorithm);
} else if (wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1)) {
return new WrapKeyTask<RsaesPkcs1Task>(aCx, aFormat, aKey,
aWrappingKey, aWrapAlgorithm);
} else if (wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
return new WrapKeyTask<RsaOaepTask>(aCx, aFormat, aKey,
aWrappingKey, aWrapAlgorithm);
}
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
}
WebCryptoTask*
WebCryptoTask::CreateUnwrapKeyTask(JSContext* aCx,
const nsAString& aFormat,
const ArrayBufferViewOrArrayBuffer& aWrappedKey,
CryptoKey& aUnwrappingKey,
const ObjectOrString& aUnwrapAlgorithm,
const ObjectOrString& aUnwrappedKeyAlgorithm,
bool aExtractable,
const Sequence<nsString>& aKeyUsages)
{
Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_UNWRAPKEY);
// Ensure key is usable for this operation
if (!aUnwrappingKey.HasUsage(CryptoKey::UNWRAPKEY)) {
return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR);
}
nsString keyAlgName;
nsresult rv = GetAlgorithmName(aCx, aUnwrappedKeyAlgorithm, keyAlgName);
if (NS_FAILED(rv)) {
return new FailureTask(rv);
}
CryptoOperationData dummy;
nsRefPtr<ImportKeyTask> importTask;
if (keyAlgName.EqualsASCII(WEBCRYPTO_ALG_AES_CBC) ||
keyAlgName.EqualsASCII(WEBCRYPTO_ALG_AES_CTR) ||
keyAlgName.EqualsASCII(WEBCRYPTO_ALG_AES_GCM) ||
keyAlgName.EqualsASCII(WEBCRYPTO_ALG_HMAC)) {
importTask = new ImportSymmetricKeyTask(aCx, aFormat, dummy,
aUnwrappedKeyAlgorithm,
aExtractable, aKeyUsages);
} else if (keyAlgName.EqualsASCII(WEBCRYPTO_ALG_RSAES_PKCS1) ||
keyAlgName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
keyAlgName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP)) {
importTask = new ImportRsaKeyTask(aCx, aFormat, dummy,
aUnwrappedKeyAlgorithm,
aExtractable, aKeyUsages);
} else {
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
}
nsString unwrapAlgName;
rv = GetAlgorithmName(aCx, aUnwrapAlgorithm, unwrapAlgName);
if (NS_FAILED(rv)) {
return new FailureTask(rv);
}
if (unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
return new UnwrapKeyTask<AesTask>(aCx, aWrappedKey,
aUnwrappingKey, aUnwrapAlgorithm,
importTask);
} else if (unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1)) {
return new UnwrapKeyTask<RsaesPkcs1Task>(aCx, aWrappedKey,
aUnwrappingKey, aUnwrapAlgorithm,
importTask);
} else if (unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
return new UnwrapKeyTask<RsaOaepTask>(aCx, aWrappedKey,
aUnwrappingKey, aUnwrapAlgorithm,
importTask);
}
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -85,13 +85,13 @@ public:
}
protected:
static WebCryptoTask* EncryptDecryptTask(JSContext* aCx,
static WebCryptoTask* CreateEncryptDecryptTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
CryptoKey& aKey,
const CryptoOperationData& aData,
bool aEncrypt);
static WebCryptoTask* SignVerifyTask(JSContext* aCx,
static WebCryptoTask* CreateSignVerifyTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
CryptoKey& aKey,
const CryptoOperationData& aSignature,
@ -99,69 +99,83 @@ protected:
bool aSign);
public:
static WebCryptoTask* EncryptTask(JSContext* aCx,
static WebCryptoTask* CreateEncryptTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
CryptoKey& aKey,
const CryptoOperationData& aData)
{
return EncryptDecryptTask(aCx, aAlgorithm, aKey, aData, true);
return CreateEncryptDecryptTask(aCx, aAlgorithm, aKey, aData, true);
}
static WebCryptoTask* DecryptTask(JSContext* aCx,
static WebCryptoTask* CreateDecryptTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
CryptoKey& aKey,
const CryptoOperationData& aData)
{
return EncryptDecryptTask(aCx, aAlgorithm, aKey, aData, false);
return CreateEncryptDecryptTask(aCx, aAlgorithm, aKey, aData, false);
}
static WebCryptoTask* SignTask(JSContext* aCx,
static WebCryptoTask* CreateSignTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
CryptoKey& aKey,
const CryptoOperationData& aData)
{
CryptoOperationData dummy;
dummy.SetAsArrayBuffer(aCx);
return SignVerifyTask(aCx, aAlgorithm, aKey, dummy, aData, true);
return CreateSignVerifyTask(aCx, aAlgorithm, aKey, dummy, aData, true);
}
static WebCryptoTask* VerifyTask(JSContext* aCx,
static WebCryptoTask* CreateVerifyTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
CryptoKey& aKey,
const CryptoOperationData& aSignature,
const CryptoOperationData& aData)
{
return SignVerifyTask(aCx, aAlgorithm, aKey, aSignature, aData, false);
return CreateSignVerifyTask(aCx, aAlgorithm, aKey, aSignature, aData, false);
}
static WebCryptoTask* DigestTask(JSContext* aCx,
static WebCryptoTask* CreateDigestTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
const CryptoOperationData& aData);
static WebCryptoTask* ImportKeyTask(JSContext* aCx,
static WebCryptoTask* CreateImportKeyTask(JSContext* aCx,
const nsAString& aFormat,
const KeyData& aKeyData,
const ObjectOrString& aAlgorithm,
bool aExtractable,
const Sequence<nsString>& aKeyUsages);
static WebCryptoTask* ExportKeyTask(const nsAString& aFormat,
static WebCryptoTask* CreateExportKeyTask(const nsAString& aFormat,
CryptoKey& aKey);
static WebCryptoTask* GenerateKeyTask(JSContext* aCx,
static WebCryptoTask* CreateGenerateKeyTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
bool aExtractable,
const Sequence<nsString>& aKeyUsages);
static WebCryptoTask* DeriveKeyTask(JSContext* aCx,
static WebCryptoTask* CreateDeriveKeyTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
CryptoKey& aBaseKey,
const ObjectOrString& aDerivedKeyType,
bool extractable,
const Sequence<nsString>& aKeyUsages);
static WebCryptoTask* DeriveBitsTask(JSContext* aCx,
static WebCryptoTask* CreateDeriveBitsTask(JSContext* aCx,
const ObjectOrString& aAlgorithm,
CryptoKey& aKey,
uint32_t aLength);
static WebCryptoTask* CreateWrapKeyTask(JSContext* aCx,
const nsAString& aFormat,
CryptoKey& aKey,
CryptoKey& aWrappingKey,
const ObjectOrString& aWrapAlgorithm);
static WebCryptoTask* CreateUnwrapKeyTask(JSContext* aCx,
const nsAString& aFormat,
const ArrayBufferViewOrArrayBuffer& aWrappedKey,
CryptoKey& aUnwrappingKey,
const ObjectOrString& aUnwrapAlgorithm,
const ObjectOrString& aUnwrappedKeyAlgorithm,
bool aExtractable,
const Sequence<nsString>& aKeyUsages);
protected:
nsRefPtr<Promise> mResultPromise;
nsresult mEarlyRv;

Просмотреть файл

@ -355,6 +355,14 @@ tv = {
),
},
key_wrap_known_answer: {
key: util.hex2abv("0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a"),
wrapping_key: util.hex2abv("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
wrapping_iv: util.hex2abv("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"),
wrapped_key: util.hex2abv("9ed0283a9a2b7e4292ebc5135e6342cc" +
"8a7f65802a1f6fd41bd3251c4da0c138")
},
// RFC 6070 <http://tools.ietf.org/html/rfc6070>
pbkdf2_sha1: {
password: new TextEncoder("utf-8").encode("passwordPASSWORDpassword"),

Просмотреть файл

@ -1274,3 +1274,158 @@ TestArray.addTest(
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"Key wrap known answer, using AES-GCM",
function () {
var that = this;
var alg = {
name: "AES-GCM",
iv: tv.key_wrap_known_answer.wrapping_iv,
tagLength: 128
};
var key, wrappingKey;
function doImport(k) {
wrappingKey = k;
return crypto.subtle.importKey("raw", tv.key_wrap_known_answer.key,
alg, true, ['encrypt', 'decrypt']);
}
function doWrap(k) {
key = k;
return crypto.subtle.wrapKey("raw", key, wrappingKey, alg);
}
crypto.subtle.importKey("raw", tv.key_wrap_known_answer.wrapping_key,
alg, false, ['wrapKey'])
.then(doImport, error(that))
.then(doWrap, error(that))
.then(
memcmp_complete(that, tv.key_wrap_known_answer.wrapped_key),
error(that)
);
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"Key wrap failing on non-extractable key",
function () {
var that = this;
var alg = {
name: "AES-GCM",
iv: tv.key_wrap_known_answer.wrapping_iv,
tagLength: 128
};
var key, wrappingKey;
function doImport(k) {
wrappingKey = k;
return crypto.subtle.importKey("raw", tv.key_wrap_known_answer.key,
alg, false, ['encrypt', 'decrypt']);
}
function doWrap(k) {
key = k;
return crypto.subtle.wrapKey("raw", key, wrappingKey, alg);
}
crypto.subtle.importKey("raw", tv.key_wrap_known_answer.wrapping_key,
alg, false, ['wrapKey'])
.then(doImport, error(that))
.then(doWrap, error(that))
.then(
error(that),
complete(that)
);
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"Key unwrap known answer, using AES-GCM",
function () {
var that = this;
var alg = {
name: "AES-GCM",
iv: tv.key_wrap_known_answer.wrapping_iv,
tagLength: 128
};
var key, wrappingKey;
function doUnwrap(k) {
wrappingKey = k;
return crypto.subtle.unwrapKey(
"raw", tv.key_wrap_known_answer.wrapped_key,
wrappingKey, alg,
"AES-GCM", true, ['encrypt', 'decrypt']
);
}
function doExport(k) {
return crypto.subtle.exportKey("raw", k);
}
crypto.subtle.importKey("raw", tv.key_wrap_known_answer.wrapping_key,
alg, false, ['unwrapKey'])
.then(doUnwrap, error(that))
.then(doExport, error(that))
.then(
memcmp_complete(that, tv.key_wrap_known_answer.key),
error(that)
);
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"Key wrap/unwrap round-trip, using RSA-OAEP",
function () {
var that = this;
var oaep = {
name: "RSA-OAEP",
hash: "SHA-256"
};
var gcm = {
name: "AES-GCM",
iv: tv.aes_gcm_enc.iv,
additionalData: tv.aes_gcm_enc.adata,
tagLength: 128
};
var unwrapKey;
function doWrap(keys) {
var originalKey = keys[0];
var wrapKey = keys[1];
unwrapKey = keys[2];
return crypto.subtle.wrapKey("raw", originalKey, wrapKey, oaep);
}
function doUnwrap(wrappedKey) {
return crypto.subtle.unwrapKey("raw", wrappedKey, unwrapKey, oaep,
gcm, false, ['encrypt']);
}
function doEncrypt(aesKey) {
return crypto.subtle.encrypt(gcm, aesKey, tv.aes_gcm_enc.data);
}
// 1.Import:
// -> HMAC key
// -> OAEP wrap key (public)
// -> OAEP unwrap key (private)
// 2. Wrap the HMAC key
// 3. Unwrap it
// 4. Compute HMAC
// 5. Check HMAC value
Promise.all([
crypto.subtle.importKey("raw", tv.aes_gcm_enc.key, gcm, true, ['encrypt']),
crypto.subtle.importKey("spki", tv.rsaoaep.spki, oaep, true, ['wrapKey']),
crypto.subtle.importKey("pkcs8", tv.rsaoaep.pkcs8, oaep, false, ['unwrapKey'])
])
.then(doWrap, error(that))
.then(doUnwrap, error(that))
.then(doEncrypt, error(that))
.then(
memcmp_complete(that, tv.aes_gcm_enc.result),
error(that)
);
}
);

Просмотреть файл

@ -176,5 +176,20 @@ interface SubtleCrypto {
sequence<KeyUsage> keyUsages );
[Throws]
Promise exportKey(KeyFormat format, CryptoKey key);
[Throws]
Promise wrapKey(KeyFormat format,
CryptoKey key,
CryptoKey wrappingKey,
AlgorithmIdentifier wrapAlgorithm);
[Throws]
Promise unwrapKey(KeyFormat format,
CryptoOperationData wrappedKey,
CryptoKey unwrappingKey,
AlgorithmIdentifier unwrapAlgorithm,
AlgorithmIdentifier unwrappedKeyAlgorithm,
boolean extractable,
sequence<KeyUsage> keyUsages );
};