Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions deps/ncrypto/ncrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,9 @@ class EVPKeyPointer final {
DER,
PEM,
JWK,
RAW_PUBLIC,
RAW_PRIVATE,
RAW_SEED,
};

enum class PKParseError { NOT_RECOGNIZED, NEED_PASSPHRASE, FAILED };
Expand All @@ -867,6 +870,7 @@ class EVPKeyPointer final {
bool output_key_object = false;
PKFormatType format = PKFormatType::DER;
PKEncodingType type = PKEncodingType::PKCS8;
int ec_point_form = POINT_CONVERSION_UNCOMPRESSED;
AsymmetricKeyEncodingConfig() = default;
AsymmetricKeyEncodingConfig(bool output_key_object,
PKFormatType format,
Expand Down
31 changes: 8 additions & 23 deletions lib/internal/crypto/aes.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const {
AESCipherJob,
KeyObjectHandle,
kCryptoJobAsync,
kKeyFormatJWK,
kKeyTypeSecret,
kKeyVariantAES_CTR_128,
kKeyVariantAES_CBC_128,
kKeyVariantAES_GCM_128,
Expand All @@ -30,7 +32,6 @@ const {
const {
hasAnyNotIn,
jobPromise,
validateKeyOps,
kHandle,
kKeyObject,
} = require('internal/crypto/util');
Expand All @@ -47,6 +48,10 @@ const {
kAlgorithm,
} = require('internal/crypto/keys');

const {
validateJwk,
} = require('internal/crypto/webcrypto_util');

const {
generateKey: _generateKey,
} = require('internal/crypto/keygen');
Expand Down Expand Up @@ -245,31 +250,11 @@ function aesImportKey(
break;
}
case 'jwk': {
if (!keyData.kty)
throw lazyDOMException('Invalid keyData', 'DataError');

if (keyData.kty !== 'oct')
throw lazyDOMException('Invalid JWK "kty" Parameter', 'DataError');

if (usagesSet.size > 0 &&
keyData.use !== undefined &&
keyData.use !== 'enc') {
throw lazyDOMException('Invalid JWK "use" Parameter', 'DataError');
}

validateKeyOps(keyData.key_ops, usagesSet);

if (keyData.ext !== undefined &&
keyData.ext === false &&
extractable === true) {
throw lazyDOMException(
'JWK "ext" Parameter and extractable mismatch',
'DataError');
}
validateJwk(keyData, 'oct', extractable, usagesSet, 'enc');

const handle = new KeyObjectHandle();
try {
handle.initJwk(keyData);
handle.init(kKeyTypeSecret, keyData, kKeyFormatJWK, null, null);
} catch (err) {
throw lazyDOMException(
'Invalid keyData', { name: 'DataError', cause: err });
Expand Down
157 changes: 20 additions & 137 deletions lib/internal/crypto/cfrg.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,22 @@ const {
TypedArrayPrototypeGetBuffer,
} = primordials;

const { Buffer } = require('buffer');

const {
KeyObjectHandle,
SignJob,
kCryptoJobAsync,
kKeyFormatDER,
kKeyTypePrivate,
kKeyTypePublic,
kKeyFormatRawPublic,
kSignJobModeSign,
kSignJobModeVerify,
kWebCryptoKeyFormatPKCS8,
kWebCryptoKeyFormatRaw,
kWebCryptoKeyFormatSPKI,
} = internalBinding('crypto');

const {
codes: {
ERR_CRYPTO_INVALID_JWK,
},
} = require('internal/errors');

const {
getUsagesUnion,
hasAnyNotIn,
jobPromise,
validateKeyOps,
kHandle,
kKeyObject,
} = require('internal/crypto/util');
Expand All @@ -48,13 +37,16 @@ const {

const {
InternalCryptoKey,
PrivateKeyObject,
PublicKeyObject,
createPrivateKey,
createPublicKey,
kKeyType,
} = require('internal/crypto/keys');

const {
importDerKey,
importJwkKey,
importRawKey,
validateJwk,
} = require('internal/crypto/webcrypto_util');

const generateKeyPair = promisify(_generateKeyPair);

function verifyAcceptableCfrgKeyUse(name, isPublic, usages) {
Expand All @@ -81,39 +73,6 @@ function verifyAcceptableCfrgKeyUse(name, isPublic, usages) {
}
}

function createCFRGRawKey(name, keyData, isPublic) {
const handle = new KeyObjectHandle();

switch (name) {
case 'Ed25519':
case 'X25519':
if (keyData.byteLength !== 32) {
throw lazyDOMException(
`${name} raw keys must be exactly 32-bytes`, 'DataError');
}
break;
case 'Ed448':
if (keyData.byteLength !== 57) {
throw lazyDOMException(
`${name} raw keys must be exactly 57-bytes`, 'DataError');
}
break;
case 'X448':
if (keyData.byteLength !== 56) {
throw lazyDOMException(
`${name} raw keys must be exactly 56-bytes`, 'DataError');
}
break;
}

const keyType = isPublic ? kKeyTypePublic : kKeyTypePrivate;
if (!handle.initEDRaw(name, keyData, keyType)) {
throw lazyDOMException('Invalid keyData', 'DataError');
}

return isPublic ? new PublicKeyObject(handle) : new PrivateKeyObject(handle);
}

async function cfrgGenerateKey(algorithm, extractable, keyUsages) {
const { name } = algorithm;

Expand Down Expand Up @@ -243,113 +202,36 @@ function cfrgImportKey(
}
case 'spki': {
verifyAcceptableCfrgKeyUse(name, true, usagesSet);
try {
keyObject = createPublicKey({
key: keyData,
format: 'der',
type: 'spki',
});
} catch (err) {
throw lazyDOMException(
'Invalid keyData', { name: 'DataError', cause: err });
}
keyObject = importDerKey(keyData, true);
break;
}
case 'pkcs8': {
verifyAcceptableCfrgKeyUse(name, false, usagesSet);
try {
keyObject = createPrivateKey({
key: keyData,
format: 'der',
type: 'pkcs8',
});
} catch (err) {
throw lazyDOMException(
'Invalid keyData', { name: 'DataError', cause: err });
}
keyObject = importDerKey(keyData, false);
break;
}
case 'jwk': {
if (!keyData.kty)
throw lazyDOMException('Invalid keyData', 'DataError');
if (keyData.kty !== 'OKP')
throw lazyDOMException('Invalid JWK "kty" Parameter', 'DataError');
const expectedUse = (name === 'X25519' || name === 'X448') ? 'enc' : 'sig';
validateJwk(keyData, 'OKP', extractable, usagesSet, expectedUse);

if (keyData.crv !== name)
throw lazyDOMException(
'JWK "crv" Parameter and algorithm name mismatch', 'DataError');
const isPublic = keyData.d === undefined;

if (usagesSet.size > 0 && keyData.use !== undefined) {
let checkUse;
switch (name) {
case 'Ed25519':
// Fall through
case 'Ed448':
checkUse = 'sig';
break;
case 'X25519':
// Fall through
case 'X448':
checkUse = 'enc';
break;
}
if (keyData.use !== checkUse)
throw lazyDOMException('Invalid JWK "use" Parameter', 'DataError');
}

validateKeyOps(keyData.key_ops, usagesSet);

if (keyData.ext !== undefined &&
keyData.ext === false &&
extractable === true) {
throw lazyDOMException(
'JWK "ext" Parameter and extractable mismatch',
'DataError');
}

if (keyData.alg !== undefined && (name === 'Ed25519' || name === 'Ed448')) {
if (keyData.alg !== name && keyData.alg !== 'EdDSA') {
if (keyData.alg !== name && keyData.alg !== 'EdDSA')
throw lazyDOMException(
'JWK "alg" does not match the requested algorithm',
'DataError');
}
'JWK "alg" does not match the requested algorithm', 'DataError');
}

if (!isPublic && typeof keyData.x !== 'string') {
throw lazyDOMException('Invalid JWK', 'DataError');
}

verifyAcceptableCfrgKeyUse(
name,
isPublic,
usagesSet);

try {
const publicKeyObject = createCFRGRawKey(
name,
Buffer.from(keyData.x, 'base64'),
true);

if (isPublic) {
keyObject = publicKeyObject;
} else {
keyObject = createCFRGRawKey(
name,
Buffer.from(keyData.d, 'base64'),
false);

if (!createPublicKey(keyObject).equals(publicKeyObject)) {
throw new ERR_CRYPTO_INVALID_JWK();
}
}
} catch (err) {
throw lazyDOMException('Invalid keyData', { name: 'DataError', cause: err });
}
const isPublic = keyData.d === undefined;
verifyAcceptableCfrgKeyUse(name, isPublic, usagesSet);
keyObject = importJwkKey(isPublic, keyData);
break;
}
case 'raw': {
verifyAcceptableCfrgKeyUse(name, true, usagesSet);
keyObject = createCFRGRawKey(name, keyData, true);
keyObject = importRawKey(true, keyData, kKeyFormatRawPublic, name);
break;
}
default:
Expand Down Expand Up @@ -381,6 +263,7 @@ async function eddsaSignVerify(key, data, algorithm, signature) {
undefined,
undefined,
undefined,
undefined,
data,
undefined,
undefined,
Expand Down
31 changes: 8 additions & 23 deletions lib/internal/crypto/chacha20_poly1305.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ const {
ChaCha20Poly1305CipherJob,
KeyObjectHandle,
kCryptoJobAsync,
kKeyFormatJWK,
kKeyTypeSecret,
} = internalBinding('crypto');

const {
hasAnyNotIn,
jobPromise,
validateKeyOps,
kHandle,
kKeyObject,
} = require('internal/crypto/util');
Expand All @@ -30,6 +31,10 @@ const {
createSecretKey,
} = require('internal/crypto/keys');

const {
validateJwk,
} = require('internal/crypto/webcrypto_util');

const {
randomBytes: _randomBytes,
} = require('internal/crypto/random');
Expand Down Expand Up @@ -107,31 +112,11 @@ function c20pImportKey(
break;
}
case 'jwk': {
if (!keyData.kty)
throw lazyDOMException('Invalid keyData', 'DataError');

if (keyData.kty !== 'oct')
throw lazyDOMException('Invalid JWK "kty" Parameter', 'DataError');

if (usagesSet.size > 0 &&
keyData.use !== undefined &&
keyData.use !== 'enc') {
throw lazyDOMException('Invalid JWK "use" Parameter', 'DataError');
}

validateKeyOps(keyData.key_ops, usagesSet);

if (keyData.ext !== undefined &&
keyData.ext === false &&
extractable === true) {
throw lazyDOMException(
'JWK "ext" Parameter and extractable mismatch',
'DataError');
}
validateJwk(keyData, 'oct', extractable, usagesSet, 'enc');

const handle = new KeyObjectHandle();
try {
handle.initJwk(keyData);
handle.init(kKeyTypeSecret, keyData, kKeyFormatJWK, null, null);
} catch (err) {
throw lazyDOMException(
'Invalid keyData', { name: 'DataError', cause: err });
Expand Down
6 changes: 3 additions & 3 deletions lib/internal/crypto/cipher.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const { StringDecoder } = require('string_decoder');

function rsaFunctionFor(method, defaultPadding, keyType) {
return (options, buffer) => {
const { format, type, data, passphrase } =
const { format, type, data, passphrase, namedCurve } =
keyType === 'private' ?
preparePrivateKey(options) :
preparePublicOrPrivateKey(options);
Expand All @@ -76,8 +76,8 @@ function rsaFunctionFor(method, defaultPadding, keyType) {
if (oaepLabel !== undefined)
oaepLabel = getArrayBufferOrView(oaepLabel, 'key.oaepLabel', encoding);
buffer = getArrayBufferOrView(buffer, 'buffer', encoding);
return method(data, format, type, passphrase, buffer, padding, oaepHash,
oaepLabel);
return method(data, format, type, passphrase, namedCurve, buffer,
padding, oaepHash, oaepLabel);
};
}

Expand Down
Loading
Loading