Skip to content

Commit 84fe3ee

Browse files
committed
chore: block js RSA-OAEP padding combination on FIPS
1 parent 48f0059 commit 84fe3ee

2 files changed

Lines changed: 50 additions & 0 deletions

File tree

‎lib/oaep.js‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
var crypto = require('crypto');
22

3+
// CRYPTO MODULE (non-FIPS-validated)
4+
// This file hand-rolls the RSA-OAEP padding (EME-OAEP encode/decode, RFC 8017
5+
// §7.1) in JavaScript. It exists only to express the OAEP-digest / MGF1-digest combinations
6+
// that Node's `crypto` cannot. Because the padding is computed here rather than inside OpenSSL,
7+
// this is not a FIPS valid code path.
8+
9+
function assertShimAllowed() {
10+
if (typeof crypto.getFips === 'function' && crypto.getFips()) {
11+
var err = new Error('unsupported cryptographic operation');
12+
err.code = 'ERR_XMLENC_FIPS_UNSUPPORTED';
13+
throw err;
14+
}
15+
}
16+
317
// MGF1 mask generation function (RFC 8017 B.2.1).
418
function mgf1(seed, length, hash) {
519
var hLen = crypto.createHash(hash).digest().length;
@@ -30,6 +44,7 @@ function decodingError() {
3044
// chosen independently. Node's privateDecrypt cannot express that combination:
3145
// it only sets the OAEP digest, and OpenSSL then defaults MGF1 to match it.
3246
function privateDecryptOaep(privateKey, ciphertext, options) {
47+
assertShimAllowed();
3348
var opts = options || {};
3449
var oaepHash = opts.oaepHash || 'sha1';
3550
var mgf1Hash = opts.mgf1Hash || oaepHash;
@@ -84,6 +99,7 @@ function privateDecryptOaep(privateKey, ciphertext, options) {
8499

85100
// EME-OAEP-ENCODE (RFC 8017 7.1.1) followed by the raw RSA public operation.
86101
function publicEncryptOaep(publicKey, message, options) {
102+
assertShimAllowed();
87103
var opts = options || {};
88104
var oaepHash = opts.oaepHash || 'sha1';
89105
var mgf1Hash = opts.mgf1Hash || oaepHash;

‎test/oaep.js‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
var assert = require('assert');
22
var crypto = require('crypto');
3+
var sinon = require('sinon');
34
var oaep = require('../lib/oaep');
45

56
// Throwaway 2048-bit key + ciphertext from the ESD-63620 repro. Produced by:
@@ -148,6 +149,39 @@ describe('oaep', function () {
148149
});
149150
});
150151

152+
describe('FIPS mode gate', function () {
153+
var fs = require('fs');
154+
var pub = fs.readFileSync(__dirname + '/test-auth0_rsa.pub');
155+
var key = fs.readFileSync(__dirname + '/test-auth0.key');
156+
157+
afterEach(function () {
158+
sinon.restore();
159+
});
160+
161+
it('refuses publicEncryptOaep when FIPS mode is enabled', function () {
162+
sinon.stub(crypto, 'getFips').returns(1);
163+
assert.throws(function () {
164+
oaep.publicEncryptOaep(pub, Buffer.from('test'), { oaepHash: 'sha256', mgf1Hash: 'sha1' });
165+
}, function (e) { return e.code === 'ERR_XMLENC_FIPS_UNSUPPORTED'; });
166+
});
167+
168+
it('refuses privateDecryptOaep when FIPS mode is enabled', function () {
169+
// Encrypt outside FIPS, then assert decrypt is blocked under FIPS.
170+
var ct = oaep.publicEncryptOaep(pub, Buffer.from('test'), { oaepHash: 'sha256', mgf1Hash: 'sha1' });
171+
sinon.stub(crypto, 'getFips').returns(1);
172+
assert.throws(function () {
173+
oaep.privateDecryptOaep(key, ct, { oaepHash: 'sha256', mgf1Hash: 'sha1' });
174+
}, function (e) { return e.code === 'ERR_XMLENC_FIPS_UNSUPPORTED'; });
175+
});
176+
177+
it('runs normally when FIPS mode is disabled', function () {
178+
sinon.stub(crypto, 'getFips').returns(0);
179+
var ct = oaep.publicEncryptOaep(pub, Buffer.from('test'), { oaepHash: 'sha256', mgf1Hash: 'sha1' });
180+
var pt = oaep.privateDecryptOaep(key, ct, { oaepHash: 'sha256', mgf1Hash: 'sha1' });
181+
assert.equal(pt.toString(), 'test');
182+
});
183+
});
184+
151185
describe('mgf1', function () {
152186
it('matches the RFC 8017 counter construction for one block', function () {
153187
var seed = Buffer.from('abc');

0 commit comments

Comments
 (0)