@@ -50,7 +50,6 @@ public:
50
50
// Add salt to digest context in order to generate or verify salted signature.
51
51
// Currently only used for RSA-PSS sign and verify operations.
52
52
53
-
54
53
// ---------------------------------------------------------------------------
55
54
// Implementation of CryptoKey
56
55
@@ -1151,7 +1150,7 @@ public:
1151
1150
1152
1151
auto outputBitLength = resultBitLength.orDefault (sharedSecret.size () * 8 );
1153
1152
JSG_REQUIRE (outputBitLength <= sharedSecret.size () * 8 , DOMOperationError,
1154
- " Derived key length (" , outputBitLength, " bits) is too long (should be less than " ,
1153
+ " Derived key length (" , outputBitLength, " bits) is too long (should be at most " ,
1155
1154
sharedSecret.size () * 8 , " bits)." );
1156
1155
1157
1156
// Round up since outputBitLength may not be a perfect multiple of 8.
@@ -1455,6 +1454,15 @@ kj::Own<EVP_PKEY> ellipticJwkReader(int curveId, SubtleCrypto::JsonWebKey keyDat
1455
1454
" Missing field \" crv\" for " , curveName, " key." );
1456
1455
JSG_REQUIRE (crv == curveName, DOMNotSupportedError,
1457
1456
" Only " , curveName, " is supported but \" " , crv, " \" was requested." );
1457
+ KJ_IF_MAYBE (alg, keyDataJwk.alg ) {
1458
+ // If this JWK specifies an algorithm, make sure it jives with the hash we were passed via
1459
+ // importKey().
1460
+ if (curveId == NID_ED25519) {
1461
+ JSG_REQUIRE (*alg == " EdDSA" , DOMDataError,
1462
+ " JSON Web Key Algorithm parameter \" alg\" (\" " , *alg, " \" ) does not match requested "
1463
+ " Ed25519 curve." );
1464
+ }
1465
+ }
1458
1466
1459
1467
auto x = UNWRAP_JWK_BIGNUM (kj::mv (keyDataJwk.x ), DOMDataError,
1460
1468
" Invalid " , crv, " key in JSON WebKey; missing or invalid public key component (\" x\" )." );
@@ -1502,7 +1510,7 @@ kj::Own<EVP_PKEY> ellipticJwkReader(int curveId, SubtleCrypto::JsonWebKey keyDat
1502
1510
" \" listed in JSON Web Key Algorithm parameter." );
1503
1511
1504
1512
JSG_REQUIRE (iter->second == curveId, DOMDataError,
1505
- " JSON Web Key Algorithm parameter \" alg\" \" " , *alg, " \" does not match requested EC curve." );
1513
+ " JSON Web Key Algorithm parameter \" alg\" ( \" " , *alg, " \" ) does not match requested curve." );
1506
1514
}
1507
1515
1508
1516
auto ecKey = OSSLCALL_OWN (EC_KEY, EC_KEY_new_by_curve_name (curveId), DOMOperationError,
@@ -1704,7 +1712,6 @@ kj::Own<CryptoKey::Impl> CryptoKey::Impl::importEcdh(
1704
1712
// =====================================================================================
1705
1713
// EDDSA & EDDH
1706
1714
1707
-
1708
1715
namespace {
1709
1716
1710
1717
// Abstract base class for EDDSA and EDDH. Unfortunately, the legacy NODE-ED25519 identifier has a
@@ -1813,6 +1820,11 @@ public:
1813
1820
" Private key for derivation is using \" " , getAlgorithmName (),
1814
1821
" \" while public key is using \" " , publicKey->getAlgorithmName (), " \" ." );
1815
1822
1823
+ auto outputBitLength = resultBitLength.orDefault (X25519_SHARED_KEY_LEN * 8 );
1824
+ JSG_REQUIRE (outputBitLength <= X25519_SHARED_KEY_LEN * 8 , DOMOperationError,
1825
+ " Derived key length (" , outputBitLength, " bits) is too long (should be at most " ,
1826
+ X25519_SHARED_KEY_LEN * 8 , " bits)." );
1827
+
1816
1828
// The check above for the algorithm `which` equality ensures that the impl can be downcast to
1817
1829
// EdDsaKey (assuming we don't accidentally create a class that doesn't inherit this one that
1818
1830
// for some reason returns an EdDsaKey).
@@ -1825,13 +1837,12 @@ public:
1825
1837
JSG_REQUIRE (1 == EVP_PKEY_derive_set_peer (ctx, publicKeyImpl.getEvpPkey ()),
1826
1838
InternalDOMOperationError, " Failed to set EDDH peer" , internalDescribeOpensslErrors ());
1827
1839
1828
- kj::Vector<kj::byte> sharedSecret (X25519_SHARED_KEY_LEN);
1829
- size_t skeylen = 0 ;
1830
- JSG_REQUIRE (1 == EVP_PKEY_derive (ctx, NULL , &skeylen), DOMOperationError,
1831
- " Failed to derive EDDH key" , internalDescribeOpensslErrors ());
1832
- KJ_ASSERT (skeylen == X25519_SHARED_KEY_LEN);
1840
+ kj::Vector<kj::byte> sharedSecret;
1841
+ sharedSecret.resize (X25519_SHARED_KEY_LEN);
1842
+ size_t skeylen = X25519_SHARED_KEY_LEN;
1833
1843
JSG_REQUIRE (1 == EVP_PKEY_derive (ctx, sharedSecret.begin (), &skeylen), DOMOperationError,
1834
1844
" Failed to derive EDDH key" , internalDescribeOpensslErrors ());
1845
+ KJ_ASSERT (skeylen == X25519_SHARED_KEY_LEN);
1835
1846
1836
1847
// Check for all-zero value as mandated by spec
1837
1848
kj::byte isNonZeroSecret = 0 ;
@@ -1840,6 +1851,14 @@ public:
1840
1851
}
1841
1852
JSG_REQUIRE (isNonZeroSecret, DOMOperationError,
1842
1853
" Detected small order secure curve points, aborting EDDH derivation" );
1854
+
1855
+ // mask off bits like in ECDH's deriveBits()
1856
+ auto resultByteLength = integerCeilDivision (outputBitLength, 8u );
1857
+ sharedSecret.truncate (resultByteLength);
1858
+ auto numBitsToMaskOff = resultByteLength * 8 - outputBitLength;
1859
+ KJ_DASSERT (numBitsToMaskOff < 8 , numBitsToMaskOff);
1860
+ uint8_t mask = ~((1 << numBitsToMaskOff) - 1 );
1861
+ sharedSecret.back () &= mask;
1843
1862
return sharedSecret.releaseAsArray ();
1844
1863
}
1845
1864
@@ -1860,6 +1879,9 @@ private:
1860
1879
jwk.kty = kj::str (" OKP" );
1861
1880
jwk.crv = kj::str (getAlgorithmName () == " X25519" _kj ? " X25519" _kj : " Ed25519" _kj);
1862
1881
jwk.x = kj::encodeBase64Url (kj::arrayPtr (rawPublicKey, publicKeyLen));
1882
+ if (getAlgorithmName () == " Ed25519" _kj) {
1883
+ jwk.alg = kj::str (" EdDSA" );
1884
+ }
1863
1885
1864
1886
if (getType () == " private" _kj) {
1865
1887
// Deliberately use ED25519_PUBLIC_KEY_LEN here.
@@ -1948,6 +1970,7 @@ kj::OneOf<jsg::Ref<CryptoKey>, CryptoKeyPair> EdDsaKeyBase::generateKey(
1948
1970
uint8_t rawPublicKey[keylen];
1949
1971
uint8_t rawPrivateKey[keylen * 2 ];
1950
1972
keypair (rawPublicKey, rawPrivateKey);
1973
+
1951
1974
// The private key technically also contains the public key. Why does the keypair function bother
1952
1975
// writing out the public key to a separate buffer?
1953
1976
0 commit comments