src: move more crypto_dh.cc code to ncrypto

Update deps/ncrypto/ncrypto.cc

PR-URL: https://github.com/nodejs/node/pull/54459
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
This commit is contained in:
James M Snell 2024-08-19 16:53:33 -07:00
parent 431ac161e6
commit 6bf7b6e342
7 changed files with 934 additions and 451 deletions

304
deps/ncrypto/dh-primes.h vendored Normal file
View File

@ -0,0 +1,304 @@
/* ====================================================================
* Copyright (c) 2011 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com). */
#include <openssl/dh.h>
#include <openssl/bn.h>
#include <openssl/err.h>
#include <openssl/mem.h>
extern "C" int bn_set_words(BIGNUM *bn, const BN_ULONG *words, size_t num);
// Backporting primes that may not be supported in earlier boringssl versions. Intentionally
// keeping the existing C-style formatting.
#define OPENSSL_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
#if defined(OPENSSL_64_BIT)
#define TOBN(hi, lo) ((BN_ULONG)(hi) << 32 | (lo))
#elif defined(OPENSSL_32_BIT)
#define TOBN(hi, lo) (lo), (hi)
#else
#error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT"
#endif
static BIGNUM *get_params(BIGNUM *ret, const BN_ULONG *words, size_t num_words) {
BIGNUM *alloc = NULL;
if (ret == NULL) {
alloc = BN_new();
if (alloc == NULL) {
return NULL;
}
ret = alloc;
}
if (!bn_set_words(ret, words, num_words)) {
BN_free(alloc);
return NULL;
}
return ret;
}
BIGNUM *BN_get_rfc3526_prime_2048(BIGNUM *ret) {
static const BN_ULONG kWords[] = {
TOBN(0xffffffff, 0xffffffff), TOBN(0x15728e5a, 0x8aacaa68),
TOBN(0x15d22618, 0x98fa0510), TOBN(0x3995497c, 0xea956ae5),
TOBN(0xde2bcbf6, 0x95581718), TOBN(0xb5c55df0, 0x6f4c52c9),
TOBN(0x9b2783a2, 0xec07a28f), TOBN(0xe39e772c, 0x180e8603),
TOBN(0x32905e46, 0x2e36ce3b), TOBN(0xf1746c08, 0xca18217c),
TOBN(0x670c354e, 0x4abc9804), TOBN(0x9ed52907, 0x7096966d),
TOBN(0x1c62f356, 0x208552bb), TOBN(0x83655d23, 0xdca3ad96),
TOBN(0x69163fa8, 0xfd24cf5f), TOBN(0x98da4836, 0x1c55d39a),
TOBN(0xc2007cb8, 0xa163bf05), TOBN(0x49286651, 0xece45b3d),
TOBN(0xae9f2411, 0x7c4b1fe6), TOBN(0xee386bfb, 0x5a899fa5),
TOBN(0x0bff5cb6, 0xf406b7ed), TOBN(0xf44c42e9, 0xa637ed6b),
TOBN(0xe485b576, 0x625e7ec6), TOBN(0x4fe1356d, 0x6d51c245),
TOBN(0x302b0a6d, 0xf25f1437), TOBN(0xef9519b3, 0xcd3a431b),
TOBN(0x514a0879, 0x8e3404dd), TOBN(0x020bbea6, 0x3b139b22),
TOBN(0x29024e08, 0x8a67cc74), TOBN(0xc4c6628b, 0x80dc1cd1),
TOBN(0xc90fdaa2, 0x2168c234), TOBN(0xffffffff, 0xffffffff),
};
return get_params(ret, kWords, OPENSSL_ARRAY_SIZE(kWords));
}
BIGNUM *BN_get_rfc3526_prime_3072(BIGNUM *ret) {
static const BN_ULONG kWords[] = {
TOBN(0xffffffff, 0xffffffff), TOBN(0x4b82d120, 0xa93ad2ca),
TOBN(0x43db5bfc, 0xe0fd108e), TOBN(0x08e24fa0, 0x74e5ab31),
TOBN(0x770988c0, 0xbad946e2), TOBN(0xbbe11757, 0x7a615d6c),
TOBN(0x521f2b18, 0x177b200c), TOBN(0xd8760273, 0x3ec86a64),
TOBN(0xf12ffa06, 0xd98a0864), TOBN(0xcee3d226, 0x1ad2ee6b),
TOBN(0x1e8c94e0, 0x4a25619d), TOBN(0xabf5ae8c, 0xdb0933d7),
TOBN(0xb3970f85, 0xa6e1e4c7), TOBN(0x8aea7157, 0x5d060c7d),
TOBN(0xecfb8504, 0x58dbef0a), TOBN(0xa85521ab, 0xdf1cba64),
TOBN(0xad33170d, 0x04507a33), TOBN(0x15728e5a, 0x8aaac42d),
TOBN(0x15d22618, 0x98fa0510), TOBN(0x3995497c, 0xea956ae5),
TOBN(0xde2bcbf6, 0x95581718), TOBN(0xb5c55df0, 0x6f4c52c9),
TOBN(0x9b2783a2, 0xec07a28f), TOBN(0xe39e772c, 0x180e8603),
TOBN(0x32905e46, 0x2e36ce3b), TOBN(0xf1746c08, 0xca18217c),
TOBN(0x670c354e, 0x4abc9804), TOBN(0x9ed52907, 0x7096966d),
TOBN(0x1c62f356, 0x208552bb), TOBN(0x83655d23, 0xdca3ad96),
TOBN(0x69163fa8, 0xfd24cf5f), TOBN(0x98da4836, 0x1c55d39a),
TOBN(0xc2007cb8, 0xa163bf05), TOBN(0x49286651, 0xece45b3d),
TOBN(0xae9f2411, 0x7c4b1fe6), TOBN(0xee386bfb, 0x5a899fa5),
TOBN(0x0bff5cb6, 0xf406b7ed), TOBN(0xf44c42e9, 0xa637ed6b),
TOBN(0xe485b576, 0x625e7ec6), TOBN(0x4fe1356d, 0x6d51c245),
TOBN(0x302b0a6d, 0xf25f1437), TOBN(0xef9519b3, 0xcd3a431b),
TOBN(0x514a0879, 0x8e3404dd), TOBN(0x020bbea6, 0x3b139b22),
TOBN(0x29024e08, 0x8a67cc74), TOBN(0xc4c6628b, 0x80dc1cd1),
TOBN(0xc90fdaa2, 0x2168c234), TOBN(0xffffffff, 0xffffffff),
};
return get_params(ret, kWords, OPENSSL_ARRAY_SIZE(kWords));
}
BIGNUM *BN_get_rfc3526_prime_4096(BIGNUM *ret) {
static const BN_ULONG kWords[] = {
TOBN(0xffffffff, 0xffffffff), TOBN(0x4df435c9, 0x34063199),
TOBN(0x86ffb7dc, 0x90a6c08f), TOBN(0x93b4ea98, 0x8d8fddc1),
TOBN(0xd0069127, 0xd5b05aa9), TOBN(0xb81bdd76, 0x2170481c),
TOBN(0x1f612970, 0xcee2d7af), TOBN(0x233ba186, 0x515be7ed),
TOBN(0x99b2964f, 0xa090c3a2), TOBN(0x287c5947, 0x4e6bc05d),
TOBN(0x2e8efc14, 0x1fbecaa6), TOBN(0xdbbbc2db, 0x04de8ef9),
TOBN(0x2583e9ca, 0x2ad44ce8), TOBN(0x1a946834, 0xb6150bda),
TOBN(0x99c32718, 0x6af4e23c), TOBN(0x88719a10, 0xbdba5b26),
TOBN(0x1a723c12, 0xa787e6d7), TOBN(0x4b82d120, 0xa9210801),
TOBN(0x43db5bfc, 0xe0fd108e), TOBN(0x08e24fa0, 0x74e5ab31),
TOBN(0x770988c0, 0xbad946e2), TOBN(0xbbe11757, 0x7a615d6c),
TOBN(0x521f2b18, 0x177b200c), TOBN(0xd8760273, 0x3ec86a64),
TOBN(0xf12ffa06, 0xd98a0864), TOBN(0xcee3d226, 0x1ad2ee6b),
TOBN(0x1e8c94e0, 0x4a25619d), TOBN(0xabf5ae8c, 0xdb0933d7),
TOBN(0xb3970f85, 0xa6e1e4c7), TOBN(0x8aea7157, 0x5d060c7d),
TOBN(0xecfb8504, 0x58dbef0a), TOBN(0xa85521ab, 0xdf1cba64),
TOBN(0xad33170d, 0x04507a33), TOBN(0x15728e5a, 0x8aaac42d),
TOBN(0x15d22618, 0x98fa0510), TOBN(0x3995497c, 0xea956ae5),
TOBN(0xde2bcbf6, 0x95581718), TOBN(0xb5c55df0, 0x6f4c52c9),
TOBN(0x9b2783a2, 0xec07a28f), TOBN(0xe39e772c, 0x180e8603),
TOBN(0x32905e46, 0x2e36ce3b), TOBN(0xf1746c08, 0xca18217c),
TOBN(0x670c354e, 0x4abc9804), TOBN(0x9ed52907, 0x7096966d),
TOBN(0x1c62f356, 0x208552bb), TOBN(0x83655d23, 0xdca3ad96),
TOBN(0x69163fa8, 0xfd24cf5f), TOBN(0x98da4836, 0x1c55d39a),
TOBN(0xc2007cb8, 0xa163bf05), TOBN(0x49286651, 0xece45b3d),
TOBN(0xae9f2411, 0x7c4b1fe6), TOBN(0xee386bfb, 0x5a899fa5),
TOBN(0x0bff5cb6, 0xf406b7ed), TOBN(0xf44c42e9, 0xa637ed6b),
TOBN(0xe485b576, 0x625e7ec6), TOBN(0x4fe1356d, 0x6d51c245),
TOBN(0x302b0a6d, 0xf25f1437), TOBN(0xef9519b3, 0xcd3a431b),
TOBN(0x514a0879, 0x8e3404dd), TOBN(0x020bbea6, 0x3b139b22),
TOBN(0x29024e08, 0x8a67cc74), TOBN(0xc4c6628b, 0x80dc1cd1),
TOBN(0xc90fdaa2, 0x2168c234), TOBN(0xffffffff, 0xffffffff),
};
return get_params(ret, kWords, OPENSSL_ARRAY_SIZE(kWords));
}
BIGNUM *BN_get_rfc3526_prime_6144(BIGNUM *ret) {
static const BN_ULONG kWords[] = {
TOBN(0xffffffff, 0xffffffff), TOBN(0xe694f91e, 0x6dcc4024),
TOBN(0x12bf2d5b, 0x0b7474d6), TOBN(0x043e8f66, 0x3f4860ee),
TOBN(0x387fe8d7, 0x6e3c0468), TOBN(0xda56c9ec, 0x2ef29632),
TOBN(0xeb19ccb1, 0xa313d55c), TOBN(0xf550aa3d, 0x8a1fbff0),
TOBN(0x06a1d58b, 0xb7c5da76), TOBN(0xa79715ee, 0xf29be328),
TOBN(0x14cc5ed2, 0x0f8037e0), TOBN(0xcc8f6d7e, 0xbf48e1d8),
TOBN(0x4bd407b2, 0x2b4154aa), TOBN(0x0f1d45b7, 0xff585ac5),
TOBN(0x23a97a7e, 0x36cc88be), TOBN(0x59e7c97f, 0xbec7e8f3),
TOBN(0xb5a84031, 0x900b1c9e), TOBN(0xd55e702f, 0x46980c82),
TOBN(0xf482d7ce, 0x6e74fef6), TOBN(0xf032ea15, 0xd1721d03),
TOBN(0x5983ca01, 0xc64b92ec), TOBN(0x6fb8f401, 0x378cd2bf),
TOBN(0x33205151, 0x2bd7af42), TOBN(0xdb7f1447, 0xe6cc254b),
TOBN(0x44ce6cba, 0xced4bb1b), TOBN(0xda3edbeb, 0xcf9b14ed),
TOBN(0x179727b0, 0x865a8918), TOBN(0xb06a53ed, 0x9027d831),
TOBN(0xe5db382f, 0x413001ae), TOBN(0xf8ff9406, 0xad9e530e),
TOBN(0xc9751e76, 0x3dba37bd), TOBN(0xc1d4dcb2, 0x602646de),
TOBN(0x36c3fab4, 0xd27c7026), TOBN(0x4df435c9, 0x34028492),
TOBN(0x86ffb7dc, 0x90a6c08f), TOBN(0x93b4ea98, 0x8d8fddc1),
TOBN(0xd0069127, 0xd5b05aa9), TOBN(0xb81bdd76, 0x2170481c),
TOBN(0x1f612970, 0xcee2d7af), TOBN(0x233ba186, 0x515be7ed),
TOBN(0x99b2964f, 0xa090c3a2), TOBN(0x287c5947, 0x4e6bc05d),
TOBN(0x2e8efc14, 0x1fbecaa6), TOBN(0xdbbbc2db, 0x04de8ef9),
TOBN(0x2583e9ca, 0x2ad44ce8), TOBN(0x1a946834, 0xb6150bda),
TOBN(0x99c32718, 0x6af4e23c), TOBN(0x88719a10, 0xbdba5b26),
TOBN(0x1a723c12, 0xa787e6d7), TOBN(0x4b82d120, 0xa9210801),
TOBN(0x43db5bfc, 0xe0fd108e), TOBN(0x08e24fa0, 0x74e5ab31),
TOBN(0x770988c0, 0xbad946e2), TOBN(0xbbe11757, 0x7a615d6c),
TOBN(0x521f2b18, 0x177b200c), TOBN(0xd8760273, 0x3ec86a64),
TOBN(0xf12ffa06, 0xd98a0864), TOBN(0xcee3d226, 0x1ad2ee6b),
TOBN(0x1e8c94e0, 0x4a25619d), TOBN(0xabf5ae8c, 0xdb0933d7),
TOBN(0xb3970f85, 0xa6e1e4c7), TOBN(0x8aea7157, 0x5d060c7d),
TOBN(0xecfb8504, 0x58dbef0a), TOBN(0xa85521ab, 0xdf1cba64),
TOBN(0xad33170d, 0x04507a33), TOBN(0x15728e5a, 0x8aaac42d),
TOBN(0x15d22618, 0x98fa0510), TOBN(0x3995497c, 0xea956ae5),
TOBN(0xde2bcbf6, 0x95581718), TOBN(0xb5c55df0, 0x6f4c52c9),
TOBN(0x9b2783a2, 0xec07a28f), TOBN(0xe39e772c, 0x180e8603),
TOBN(0x32905e46, 0x2e36ce3b), TOBN(0xf1746c08, 0xca18217c),
TOBN(0x670c354e, 0x4abc9804), TOBN(0x9ed52907, 0x7096966d),
TOBN(0x1c62f356, 0x208552bb), TOBN(0x83655d23, 0xdca3ad96),
TOBN(0x69163fa8, 0xfd24cf5f), TOBN(0x98da4836, 0x1c55d39a),
TOBN(0xc2007cb8, 0xa163bf05), TOBN(0x49286651, 0xece45b3d),
TOBN(0xae9f2411, 0x7c4b1fe6), TOBN(0xee386bfb, 0x5a899fa5),
TOBN(0x0bff5cb6, 0xf406b7ed), TOBN(0xf44c42e9, 0xa637ed6b),
TOBN(0xe485b576, 0x625e7ec6), TOBN(0x4fe1356d, 0x6d51c245),
TOBN(0x302b0a6d, 0xf25f1437), TOBN(0xef9519b3, 0xcd3a431b),
TOBN(0x514a0879, 0x8e3404dd), TOBN(0x020bbea6, 0x3b139b22),
TOBN(0x29024e08, 0x8a67cc74), TOBN(0xc4c6628b, 0x80dc1cd1),
TOBN(0xc90fdaa2, 0x2168c234), TOBN(0xffffffff, 0xffffffff),
};
return get_params(ret, kWords, OPENSSL_ARRAY_SIZE(kWords));
}
BIGNUM *BN_get_rfc3526_prime_8192(BIGNUM *ret) {
static const BN_ULONG kWords[] = {
TOBN(0xffffffff, 0xffffffff), TOBN(0x60c980dd, 0x98edd3df),
TOBN(0xc81f56e8, 0x80b96e71), TOBN(0x9e3050e2, 0x765694df),
TOBN(0x9558e447, 0x5677e9aa), TOBN(0xc9190da6, 0xfc026e47),
TOBN(0x889a002e, 0xd5ee382b), TOBN(0x4009438b, 0x481c6cd7),
TOBN(0x359046f4, 0xeb879f92), TOBN(0xfaf36bc3, 0x1ecfa268),
TOBN(0xb1d510bd, 0x7ee74d73), TOBN(0xf9ab4819, 0x5ded7ea1),
TOBN(0x64f31cc5, 0x0846851d), TOBN(0x4597e899, 0xa0255dc1),
TOBN(0xdf310ee0, 0x74ab6a36), TOBN(0x6d2a13f8, 0x3f44f82d),
TOBN(0x062b3cf5, 0xb3a278a6), TOBN(0x79683303, 0xed5bdd3a),
TOBN(0xfa9d4b7f, 0xa2c087e8), TOBN(0x4bcbc886, 0x2f8385dd),
TOBN(0x3473fc64, 0x6cea306b), TOBN(0x13eb57a8, 0x1a23f0c7),
TOBN(0x22222e04, 0xa4037c07), TOBN(0xe3fdb8be, 0xfc848ad9),
TOBN(0x238f16cb, 0xe39d652d), TOBN(0x3423b474, 0x2bf1c978),
TOBN(0x3aab639c, 0x5ae4f568), TOBN(0x2576f693, 0x6ba42466),
TOBN(0x741fa7bf, 0x8afc47ed), TOBN(0x3bc832b6, 0x8d9dd300),
TOBN(0xd8bec4d0, 0x73b931ba), TOBN(0x38777cb6, 0xa932df8c),
TOBN(0x74a3926f, 0x12fee5e4), TOBN(0xe694f91e, 0x6dbe1159),
TOBN(0x12bf2d5b, 0x0b7474d6), TOBN(0x043e8f66, 0x3f4860ee),
TOBN(0x387fe8d7, 0x6e3c0468), TOBN(0xda56c9ec, 0x2ef29632),
TOBN(0xeb19ccb1, 0xa313d55c), TOBN(0xf550aa3d, 0x8a1fbff0),
TOBN(0x06a1d58b, 0xb7c5da76), TOBN(0xa79715ee, 0xf29be328),
TOBN(0x14cc5ed2, 0x0f8037e0), TOBN(0xcc8f6d7e, 0xbf48e1d8),
TOBN(0x4bd407b2, 0x2b4154aa), TOBN(0x0f1d45b7, 0xff585ac5),
TOBN(0x23a97a7e, 0x36cc88be), TOBN(0x59e7c97f, 0xbec7e8f3),
TOBN(0xb5a84031, 0x900b1c9e), TOBN(0xd55e702f, 0x46980c82),
TOBN(0xf482d7ce, 0x6e74fef6), TOBN(0xf032ea15, 0xd1721d03),
TOBN(0x5983ca01, 0xc64b92ec), TOBN(0x6fb8f401, 0x378cd2bf),
TOBN(0x33205151, 0x2bd7af42), TOBN(0xdb7f1447, 0xe6cc254b),
TOBN(0x44ce6cba, 0xced4bb1b), TOBN(0xda3edbeb, 0xcf9b14ed),
TOBN(0x179727b0, 0x865a8918), TOBN(0xb06a53ed, 0x9027d831),
TOBN(0xe5db382f, 0x413001ae), TOBN(0xf8ff9406, 0xad9e530e),
TOBN(0xc9751e76, 0x3dba37bd), TOBN(0xc1d4dcb2, 0x602646de),
TOBN(0x36c3fab4, 0xd27c7026), TOBN(0x4df435c9, 0x34028492),
TOBN(0x86ffb7dc, 0x90a6c08f), TOBN(0x93b4ea98, 0x8d8fddc1),
TOBN(0xd0069127, 0xd5b05aa9), TOBN(0xb81bdd76, 0x2170481c),
TOBN(0x1f612970, 0xcee2d7af), TOBN(0x233ba186, 0x515be7ed),
TOBN(0x99b2964f, 0xa090c3a2), TOBN(0x287c5947, 0x4e6bc05d),
TOBN(0x2e8efc14, 0x1fbecaa6), TOBN(0xdbbbc2db, 0x04de8ef9),
TOBN(0x2583e9ca, 0x2ad44ce8), TOBN(0x1a946834, 0xb6150bda),
TOBN(0x99c32718, 0x6af4e23c), TOBN(0x88719a10, 0xbdba5b26),
TOBN(0x1a723c12, 0xa787e6d7), TOBN(0x4b82d120, 0xa9210801),
TOBN(0x43db5bfc, 0xe0fd108e), TOBN(0x08e24fa0, 0x74e5ab31),
TOBN(0x770988c0, 0xbad946e2), TOBN(0xbbe11757, 0x7a615d6c),
TOBN(0x521f2b18, 0x177b200c), TOBN(0xd8760273, 0x3ec86a64),
TOBN(0xf12ffa06, 0xd98a0864), TOBN(0xcee3d226, 0x1ad2ee6b),
TOBN(0x1e8c94e0, 0x4a25619d), TOBN(0xabf5ae8c, 0xdb0933d7),
TOBN(0xb3970f85, 0xa6e1e4c7), TOBN(0x8aea7157, 0x5d060c7d),
TOBN(0xecfb8504, 0x58dbef0a), TOBN(0xa85521ab, 0xdf1cba64),
TOBN(0xad33170d, 0x04507a33), TOBN(0x15728e5a, 0x8aaac42d),
TOBN(0x15d22618, 0x98fa0510), TOBN(0x3995497c, 0xea956ae5),
TOBN(0xde2bcbf6, 0x95581718), TOBN(0xb5c55df0, 0x6f4c52c9),
TOBN(0x9b2783a2, 0xec07a28f), TOBN(0xe39e772c, 0x180e8603),
TOBN(0x32905e46, 0x2e36ce3b), TOBN(0xf1746c08, 0xca18217c),
TOBN(0x670c354e, 0x4abc9804), TOBN(0x9ed52907, 0x7096966d),
TOBN(0x1c62f356, 0x208552bb), TOBN(0x83655d23, 0xdca3ad96),
TOBN(0x69163fa8, 0xfd24cf5f), TOBN(0x98da4836, 0x1c55d39a),
TOBN(0xc2007cb8, 0xa163bf05), TOBN(0x49286651, 0xece45b3d),
TOBN(0xae9f2411, 0x7c4b1fe6), TOBN(0xee386bfb, 0x5a899fa5),
TOBN(0x0bff5cb6, 0xf406b7ed), TOBN(0xf44c42e9, 0xa637ed6b),
TOBN(0xe485b576, 0x625e7ec6), TOBN(0x4fe1356d, 0x6d51c245),
TOBN(0x302b0a6d, 0xf25f1437), TOBN(0xef9519b3, 0xcd3a431b),
TOBN(0x514a0879, 0x8e3404dd), TOBN(0x020bbea6, 0x3b139b22),
TOBN(0x29024e08, 0x8a67cc74), TOBN(0xc4c6628b, 0x80dc1cd1),
TOBN(0xc90fdaa2, 0x2168c234), TOBN(0xffffffff, 0xffffffff),
};
return get_params(ret, kWords, OPENSSL_ARRAY_SIZE(kWords));
}

View File

@ -1,6 +1,7 @@
#include "ncrypto.h" #include "ncrypto.h"
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <openssl/dh.h>
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/pkcs12.h> #include <openssl/pkcs12.h>
@ -8,6 +9,9 @@
#if OPENSSL_VERSION_MAJOR >= 3 #if OPENSSL_VERSION_MAJOR >= 3
#include <openssl/provider.h> #include <openssl/provider.h>
#endif #endif
#ifdef OPENSSL_IS_BORINGSSL
#include "dh-primes.h"
#endif // OPENSSL_IS_BORINGSSL
namespace ncrypto { namespace ncrypto {
namespace { namespace {
@ -289,6 +293,11 @@ const BIGNUM* BignumPointer::One() {
return BN_value_one(); return BN_value_one();
} }
BignumPointer BignumPointer::clone() {
if (!bn_) return {};
return BignumPointer(BN_dup(bn_.get()));
}
// ============================================================================ // ============================================================================
// Utility methods // Utility methods
@ -1016,4 +1025,231 @@ int BIOPointer::Write(BIOPointer* bio, std::string_view message) {
return BIO_write(bio->get(), message.data(), message.size()); return BIO_write(bio->get(), message.data(), message.size());
} }
// ============================================================================
// DHPointer
namespace {
bool EqualNoCase(const std::string_view a, const std::string_view b) {
if (a.size() != b.size()) return false;
return std::equal(a.begin(), a.end(), b.begin(), b.end(),
[](char a, char b) { return std::tolower(a) == std::tolower(b); });
}
} // namespace
DHPointer::DHPointer(DH* dh) : dh_(dh) {}
DHPointer::DHPointer(DHPointer&& other) noexcept : dh_(other.release()) {}
DHPointer& DHPointer::operator=(DHPointer&& other) noexcept {
if (this == &other) return *this;
this->~DHPointer();
return *new (this) DHPointer(std::move(other));
}
DHPointer::~DHPointer() { reset(); }
void DHPointer::reset(DH* dh) { dh_.reset(dh); }
DH* DHPointer::release() { return dh_.release(); }
BignumPointer DHPointer::FindGroup(const std::string_view name,
FindGroupOption option) {
#define V(n, p) if (EqualNoCase(name, n)) return BignumPointer(p(nullptr));
if (option != FindGroupOption::NO_SMALL_PRIMES) {
V("modp1", BN_get_rfc2409_prime_768);
V("modp2", BN_get_rfc2409_prime_1024);
V("modp5", BN_get_rfc3526_prime_1536);
}
V("modp14", BN_get_rfc3526_prime_2048);
V("modp15", BN_get_rfc3526_prime_3072);
V("modp16", BN_get_rfc3526_prime_4096);
V("modp17", BN_get_rfc3526_prime_6144);
V("modp18", BN_get_rfc3526_prime_8192);
#undef V
return {};
}
BignumPointer DHPointer::GetStandardGenerator() {
auto bn = BignumPointer::New();
if (!bn) return {};
if (!bn.setWord(DH_GENERATOR_2)) return {};
return bn;
}
DHPointer DHPointer::FromGroup(const std::string_view name,
FindGroupOption option) {
auto group = FindGroup(name, option);
if (!group) return {}; // Unable to find the named group.
auto generator = GetStandardGenerator();
if (!generator) return {}; // Unable to create the generator.
return New(std::move(group), std::move(generator));
}
DHPointer DHPointer::New(BignumPointer&& p, BignumPointer&& g) {
if (!p || !g) return {};
DHPointer dh(DH_new());
if (!dh) return {};
if (DH_set0_pqg(dh.get(), p.get(), nullptr, g.get()) != 1) return {};
// If the call above is successful, the DH object takes ownership of the
// BIGNUMs, so we must release them here.
p.release();
g.release();
return dh;
}
DHPointer DHPointer::New(size_t bits, unsigned int generator) {
DHPointer dh(DH_new());
if (!dh) return {};
if (DH_generate_parameters_ex(dh.get(), bits, generator, nullptr) != 1) {
return {};
}
return dh;
}
DHPointer::CheckResult DHPointer::check() {
ClearErrorOnReturn clearErrorOnReturn;
if (!dh_) return DHPointer::CheckResult::NONE;
int codes = 0;
if (DH_check(dh_.get(), &codes) != 1)
return DHPointer::CheckResult::CHECK_FAILED;
return static_cast<CheckResult>(codes);
}
DHPointer::CheckPublicKeyResult DHPointer::checkPublicKey(const BignumPointer& pub_key) {
ClearErrorOnReturn clearErrorOnReturn;
if (!pub_key || !dh_) return DHPointer::CheckPublicKeyResult::CHECK_FAILED;
int codes = 0;
if (DH_check_pub_key(dh_.get(), pub_key.get(), &codes) != 1)
return DHPointer::CheckPublicKeyResult::CHECK_FAILED;
if (codes & DH_CHECK_PUBKEY_TOO_SMALL) {
return DHPointer::CheckPublicKeyResult::TOO_SMALL;
} else if (codes & DH_CHECK_PUBKEY_TOO_SMALL) {
return DHPointer::CheckPublicKeyResult::TOO_LARGE;
} else if (codes != 0) {
return DHPointer::CheckPublicKeyResult::INVALID;
}
return CheckPublicKeyResult::NONE;
}
DataPointer DHPointer::getPrime() const {
if (!dh_) return {};
const BIGNUM* p;
DH_get0_pqg(dh_.get(), &p, nullptr, nullptr);
return BignumPointer::Encode(p);
}
DataPointer DHPointer::getGenerator() const {
if (!dh_) return {};
const BIGNUM* g;
DH_get0_pqg(dh_.get(), nullptr, nullptr, &g);
return BignumPointer::Encode(g);
}
DataPointer DHPointer::getPublicKey() const {
if (!dh_) return {};
const BIGNUM* pub_key;
DH_get0_key(dh_.get(), &pub_key, nullptr);
return BignumPointer::Encode(pub_key);
}
DataPointer DHPointer::getPrivateKey() const {
if (!dh_) return {};
const BIGNUM* pvt_key;
DH_get0_key(dh_.get(), nullptr, &pvt_key);
return BignumPointer::Encode(pvt_key);
}
DataPointer DHPointer::generateKeys() const {
ClearErrorOnReturn clearErrorOnReturn;
if (!dh_) return {};
// Key generation failed
if (!DH_generate_key(dh_.get())) return {};
return getPublicKey();
}
size_t DHPointer::size() const {
if (!dh_) return 0;
return DH_size(dh_.get());
}
DataPointer DHPointer::computeSecret(const BignumPointer& peer) const {
ClearErrorOnReturn clearErrorOnReturn;
if (!dh_ || !peer) return {};
auto dp = DataPointer::Alloc(size());
if (!dp) return {};
int size = DH_compute_key(static_cast<uint8_t*>(dp.get()), peer.get(), dh_.get());
if (size < 0) return {};
// The size of the computed key can be smaller than the size of the DH key.
// We want to make sure that the key is correctly padded.
if (size < dp.size()) {
const size_t padding = dp.size() - size;
uint8_t* data = static_cast<uint8_t*>(dp.get());
memmove(data + padding, data, size);
memset(data, 0, padding);
}
return dp;
}
bool DHPointer::setPublicKey(BignumPointer&& key) {
if (!dh_) return false;
if (DH_set0_key(dh_.get(), key.get(), nullptr) == 1) {
key.release();
return true;
}
return false;
}
bool DHPointer::setPrivateKey(BignumPointer&& key) {
if (!dh_) return false;
if (DH_set0_key(dh_.get(), nullptr, key.get()) == 1) {
key.release();
return true;
}
return false;
}
DataPointer DHPointer::stateless(const EVPKeyPointer& ourKey,
const EVPKeyPointer& theirKey) {
size_t out_size;
if (!ourKey || !theirKey) return {};
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(ourKey.get(), nullptr));
if (!ctx ||
EVP_PKEY_derive_init(ctx.get()) <= 0 ||
EVP_PKEY_derive_set_peer(ctx.get(), theirKey.get()) <= 0 ||
EVP_PKEY_derive(ctx.get(), nullptr, &out_size) <= 0) {
return {};
}
if (out_size == 0) return {};
auto out = DataPointer::Alloc(out_size);
if (EVP_PKEY_derive(ctx.get(), reinterpret_cast<uint8_t*>(out.get()), &out_size) <= 0) {
return {};
}
if (out_size < out.size()) {
const size_t padding = out.size() - out_size;
uint8_t* data = static_cast<uint8_t*>(out.get());
memmove(data + padding, data, out_size);
memset(data, 0, padding);
}
return out;
}
} // namespace ncrypto } // namespace ncrypto

View File

@ -2,6 +2,7 @@
'variables': { 'variables': {
'ncrypto_sources': [ 'ncrypto_sources': [
'engine.cc', 'engine.cc',
'dh-primes.h',
'ncrypto.cc', 'ncrypto.cc',
'ncrypto.h', 'ncrypto.h',
], ],

View File

@ -194,7 +194,6 @@ using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;
using BignumCtxPointer = DeleteFnPtr<BN_CTX, BN_CTX_free>; using BignumCtxPointer = DeleteFnPtr<BN_CTX, BN_CTX_free>;
using CipherCtxPointer = DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>; using CipherCtxPointer = DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>;
using DHPointer = DeleteFnPtr<DH, DH_free>;
using DSAPointer = DeleteFnPtr<DSA, DSA_free>; using DSAPointer = DeleteFnPtr<DSA, DSA_free>;
using DSASigPointer = DeleteFnPtr<DSA_SIG, DSA_SIG_free>; using DSASigPointer = DeleteFnPtr<DSA_SIG, DSA_SIG_free>;
using ECDSASigPointer = DeleteFnPtr<ECDSA_SIG, ECDSA_SIG_free>; using ECDSASigPointer = DeleteFnPtr<ECDSA_SIG, ECDSA_SIG_free>;
@ -354,10 +353,88 @@ class BignumPointer final {
static unsigned long GetWord(const BIGNUM* bn); static unsigned long GetWord(const BIGNUM* bn);
static const BIGNUM* One(); static const BIGNUM* One();
BignumPointer clone();
private: private:
DeleteFnPtr<BIGNUM, BN_clear_free> bn_; DeleteFnPtr<BIGNUM, BN_clear_free> bn_;
}; };
class DHPointer final {
public:
enum class FindGroupOption {
NONE,
// There are known and documented security issues with prime groups smaller
// than 2048 bits. When the NO_SMALL_PRIMES option is set, these small prime
// groups will not be supported.
NO_SMALL_PRIMES,
};
static BignumPointer GetStandardGenerator();
static BignumPointer FindGroup(const std::string_view name,
FindGroupOption option = FindGroupOption::NONE);
static DHPointer FromGroup(const std::string_view name,
FindGroupOption option = FindGroupOption::NONE);
static DHPointer New(BignumPointer&& p, BignumPointer&& g);
static DHPointer New(size_t bits, unsigned int generator);
DHPointer() = default;
explicit DHPointer(DH* dh);
DHPointer(DHPointer&& other) noexcept;
DHPointer& operator=(DHPointer&& other) noexcept;
NCRYPTO_DISALLOW_COPY(DHPointer)
~DHPointer();
inline bool operator==(std::nullptr_t) noexcept { return dh_ == nullptr; }
inline operator bool() const { return dh_ != nullptr; }
inline DH* get() const { return dh_.get(); }
void reset(DH* dh = nullptr);
DH* release();
enum class CheckResult {
NONE,
P_NOT_PRIME = DH_CHECK_P_NOT_PRIME,
P_NOT_SAFE_PRIME = DH_CHECK_P_NOT_SAFE_PRIME,
UNABLE_TO_CHECK_GENERATOR = DH_UNABLE_TO_CHECK_GENERATOR,
NOT_SUITABLE_GENERATOR = DH_NOT_SUITABLE_GENERATOR,
Q_NOT_PRIME = DH_CHECK_Q_NOT_PRIME,
INVALID_Q = DH_CHECK_INVALID_Q_VALUE,
INVALID_J = DH_CHECK_INVALID_J_VALUE,
CHECK_FAILED = 512,
};
CheckResult check();
enum class CheckPublicKeyResult {
NONE,
TOO_SMALL = DH_R_CHECK_PUBKEY_TOO_SMALL,
TOO_LARGE = DH_R_CHECK_PUBKEY_TOO_LARGE,
INVALID = DH_R_CHECK_PUBKEY_INVALID,
CHECK_FAILED = 512,
};
// Check to see if the given public key is suitable for this DH instance.
CheckPublicKeyResult checkPublicKey(const BignumPointer& pub_key);
DataPointer getPrime() const;
DataPointer getGenerator() const;
DataPointer getPublicKey() const;
DataPointer getPrivateKey() const;
DataPointer generateKeys() const;
DataPointer computeSecret(const BignumPointer& peer) const;
bool setPublicKey(BignumPointer&& key);
bool setPrivateKey(BignumPointer&& key);
size_t size() const;
static DataPointer stateless(const EVPKeyPointer& ourKey,
const EVPKeyPointer& theirKey);
private:
DeleteFnPtr<DH, DH_free> dh_;
};
class X509Pointer; class X509Pointer;
class X509View final { class X509View final {

View File

@ -5,27 +5,28 @@
#include "crypto/crypto_util.h" #include "crypto/crypto_util.h"
#include "env-inl.h" #include "env-inl.h"
#include "memory_tracker-inl.h" #include "memory_tracker-inl.h"
#include "ncrypto.h"
#include "node_errors.h"
#include "openssl/bnerr.h"
#include "openssl/dh.h"
#include "threadpoolwork-inl.h" #include "threadpoolwork-inl.h"
#include "v8.h" #include "v8.h"
#include <variant>
namespace node { namespace node {
using v8::ArrayBuffer; using v8::ArrayBuffer;
using v8::BackingStore;
using v8::ConstructorBehavior; using v8::ConstructorBehavior;
using v8::Context; using v8::Context;
using v8::DontDelete; using v8::DontDelete;
using v8::FunctionCallback; using v8::FunctionCallback;
using v8::FunctionCallbackInfo; using v8::FunctionCallbackInfo;
using v8::FunctionTemplate; using v8::FunctionTemplate;
using v8::HandleScope;
using v8::Int32; using v8::Int32;
using v8::Isolate; using v8::Isolate;
using v8::Just; using v8::Just;
using v8::Local; using v8::Local;
using v8::Maybe; using v8::Maybe;
using v8::MaybeLocal;
using v8::Nothing; using v8::Nothing;
using v8::Object; using v8::Object;
using v8::PropertyAttribute; using v8::PropertyAttribute;
@ -36,361 +37,219 @@ using v8::String;
using v8::Value; using v8::Value;
namespace crypto { namespace crypto {
namespace { DiffieHellman::DiffieHellman(Environment* env, Local<Object> wrap, DHPointer dh)
void ZeroPadDiffieHellmanSecret(size_t remainder_size, : BaseObject(env, wrap), dh_(std::move(dh)) {
char* data,
size_t length) {
// DH_size returns number of bytes in a prime number.
// DH_compute_key returns number of bytes in a remainder of exponent, which
// may have less bytes than a prime number. Therefore add 0-padding to the
// allocated buffer.
const size_t prime_size = length;
if (remainder_size != prime_size) {
CHECK_LT(remainder_size, prime_size);
const size_t padding = prime_size - remainder_size;
memmove(data + padding, data, remainder_size);
memset(data, 0, padding);
}
}
} // namespace
DiffieHellman::DiffieHellman(Environment* env, Local<Object> wrap)
: BaseObject(env, wrap), verifyError_(0) {
MakeWeak(); MakeWeak();
} }
void DiffieHellman::Initialize(Environment* env, Local<Object> target) {
Isolate* isolate = env->isolate();
Local<Context> context = env->context();
auto make = [&](Local<String> name, FunctionCallback callback) {
Local<FunctionTemplate> t = NewFunctionTemplate(isolate, callback);
const PropertyAttribute attributes =
static_cast<PropertyAttribute>(ReadOnly | DontDelete);
t->InstanceTemplate()->SetInternalFieldCount(
DiffieHellman::kInternalFieldCount);
SetProtoMethod(isolate, t, "generateKeys", GenerateKeys);
SetProtoMethod(isolate, t, "computeSecret", ComputeSecret);
SetProtoMethodNoSideEffect(isolate, t, "getPrime", GetPrime);
SetProtoMethodNoSideEffect(isolate, t, "getGenerator", GetGenerator);
SetProtoMethodNoSideEffect(isolate, t, "getPublicKey", GetPublicKey);
SetProtoMethodNoSideEffect(isolate, t, "getPrivateKey", GetPrivateKey);
SetProtoMethod(isolate, t, "setPublicKey", SetPublicKey);
SetProtoMethod(isolate, t, "setPrivateKey", SetPrivateKey);
Local<FunctionTemplate> verify_error_getter_templ =
FunctionTemplate::New(isolate,
DiffieHellman::VerifyErrorGetter,
Local<Value>(),
Signature::New(env->isolate(), t),
/* length */ 0,
ConstructorBehavior::kThrow,
SideEffectType::kHasNoSideEffect);
t->InstanceTemplate()->SetAccessorProperty(
env->verify_error_string(),
verify_error_getter_templ,
Local<FunctionTemplate>(),
attributes);
SetConstructorFunction(context, target, name, t);
};
make(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellman"), New);
make(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellmanGroup"),
DiffieHellmanGroup);
SetMethodNoSideEffect(
context, target, "statelessDH", DiffieHellman::Stateless);
DHKeyPairGenJob::Initialize(env, target);
DHKeyExportJob::Initialize(env, target);
DHBitsJob::Initialize(env, target);
}
void DiffieHellman::RegisterExternalReferences(
ExternalReferenceRegistry* registry) {
registry->Register(New);
registry->Register(DiffieHellmanGroup);
registry->Register(GenerateKeys);
registry->Register(ComputeSecret);
registry->Register(GetPrime);
registry->Register(GetGenerator);
registry->Register(GetPublicKey);
registry->Register(GetPrivateKey);
registry->Register(SetPublicKey);
registry->Register(SetPrivateKey);
registry->Register(DiffieHellman::VerifyErrorGetter);
registry->Register(DiffieHellman::Stateless);
DHKeyPairGenJob::RegisterExternalReferences(registry);
DHKeyExportJob::RegisterExternalReferences(registry);
DHBitsJob::RegisterExternalReferences(registry);
}
bool DiffieHellman::Init(int primeLength, int g) {
dh_.reset(DH_new());
if (!DH_generate_parameters_ex(dh_.get(), primeLength, g, nullptr))
return false;
return VerifyContext();
}
void DiffieHellman::MemoryInfo(MemoryTracker* tracker) const { void DiffieHellman::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackFieldWithSize("dh", dh_ ? kSizeOf_DH : 0); tracker->TrackFieldWithSize("dh", dh_ ? kSizeOf_DH : 0);
} }
namespace { namespace {
bool SetDhParams(DH* dh, BignumPointer* p, BignumPointer* g) { MaybeLocal<Value> DataPointerToBuffer(Environment* env,
// If DH_set0_pqg returns 0, ownership of the input parameters has ncrypto::DataPointer&& data) {
// not been transferred to the DH object. If the return value is 1, auto backing = ArrayBuffer::NewBackingStore(
// ownership has been transferred and we need to release them. data.get(),
// The documentation for DH_set0_pqg is not clear on this point. data.size(),
// It says that ownership is transfered when the method is called [](void* data, size_t len, void* ptr) {
// but there is an internal check that returns 0 if the input is ncrypto::DataPointer free_ne(data, len);
// not valid, and in that case ownership is not transferred. },
if (DH_set0_pqg(dh, p->get(), nullptr, g->get()) == 0) return false; nullptr);
p->release(); data.release();
g->release();
return true;
}
} // namespace
bool DiffieHellman::Init(BignumPointer&& bn_p, int g) { auto ab = ArrayBuffer::New(env->isolate(), std::move(backing));
dh_.reset(DH_new()); return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>());
CHECK_GE(g, 2);
auto bn_g = BignumPointer::New();
return bn_p && bn_g.setWord(g) && SetDhParams(dh_.get(), &bn_p, &bn_g) &&
VerifyContext();
} }
bool DiffieHellman::Init(const char* p, int p_len, int g) { void DiffieHellmanGroup(const FunctionCallbackInfo<Value>& args) {
dh_.reset(DH_new());
if (p_len <= 0) {
ERR_put_error(ERR_LIB_BN, BN_F_BN_GENERATE_PRIME_EX,
BN_R_BITS_TOO_SMALL, __FILE__, __LINE__);
return false;
}
if (g <= 1) {
ERR_put_error(ERR_LIB_DH, DH_F_DH_BUILTIN_GENPARAMS,
DH_R_BAD_GENERATOR, __FILE__, __LINE__);
return false;
}
BignumPointer bn_p(reinterpret_cast<const unsigned char*>(p), p_len);
auto bn_g = BignumPointer::New();
return bn_p && bn_g.setWord(g) && SetDhParams(dh_.get(), &bn_p, &bn_g) &&
VerifyContext();
}
bool DiffieHellman::Init(const char* p, int p_len, const char* g, int g_len) {
dh_.reset(DH_new());
if (p_len <= 0) {
ERR_put_error(ERR_LIB_BN, BN_F_BN_GENERATE_PRIME_EX,
BN_R_BITS_TOO_SMALL, __FILE__, __LINE__);
return false;
}
if (g_len <= 0) {
ERR_put_error(ERR_LIB_DH, DH_F_DH_BUILTIN_GENPARAMS,
DH_R_BAD_GENERATOR, __FILE__, __LINE__);
return false;
}
BignumPointer bn_g(reinterpret_cast<const unsigned char*>(g), g_len);
if (!bn_g || bn_g.isZero() || bn_g.isOne()) {
ERR_put_error(ERR_LIB_DH, DH_F_DH_BUILTIN_GENPARAMS,
DH_R_BAD_GENERATOR, __FILE__, __LINE__);
return false;
}
BignumPointer bn_p(reinterpret_cast<const unsigned char*>(p), p_len);
return bn_p && SetDhParams(dh_.get(), &bn_p, &bn_g) && VerifyContext();
}
constexpr int kStandardizedGenerator = 2;
template <BIGNUM* (*p)(BIGNUM*)>
BignumPointer InstantiateStandardizedGroup() {
return BignumPointer(p(nullptr));
}
typedef BignumPointer (*StandardizedGroupInstantiator)();
// Returns a function that can be used to create an instance of a standardized
// Diffie-Hellman group. The generator is always kStandardizedGenerator.
inline StandardizedGroupInstantiator FindDiffieHellmanGroup(const char* name) {
#define V(n, p) \
if (StringEqualNoCase(name, n)) return InstantiateStandardizedGroup<p>
V("modp1", BN_get_rfc2409_prime_768);
V("modp2", BN_get_rfc2409_prime_1024);
V("modp5", BN_get_rfc3526_prime_1536);
V("modp14", BN_get_rfc3526_prime_2048);
V("modp15", BN_get_rfc3526_prime_3072);
V("modp16", BN_get_rfc3526_prime_4096);
V("modp17", BN_get_rfc3526_prime_6144);
V("modp18", BN_get_rfc3526_prime_8192);
#undef V
return nullptr;
}
void DiffieHellman::DiffieHellmanGroup(
const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args); Environment* env = Environment::GetCurrent(args);
DiffieHellman* diffieHellman = new DiffieHellman(env, args.This());
CHECK_EQ(args.Length(), 1); CHECK_EQ(args.Length(), 1);
THROW_AND_RETURN_IF_NOT_STRING(env, args[0], "Group name"); THROW_AND_RETURN_IF_NOT_STRING(env, args[0], "Group name");
bool initialized = false;
const node::Utf8Value group_name(env->isolate(), args[0]); const node::Utf8Value group_name(env->isolate(), args[0]);
auto group = FindDiffieHellmanGroup(*group_name);
if (group == nullptr)
return THROW_ERR_CRYPTO_UNKNOWN_DH_GROUP(env);
initialized = diffieHellman->Init(group(), kStandardizedGenerator); DHPointer dh = DHPointer::FromGroup(group_name.ToStringView());
if (!initialized) if (!dh) {
THROW_ERR_CRYPTO_INITIALIZATION_FAILED(env); return THROW_ERR_CRYPTO_UNKNOWN_DH_GROUP(env);
}
new DiffieHellman(env, args.This(), std::move(dh));
} }
void New(const FunctionCallbackInfo<Value>& args) {
void DiffieHellman::New(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args); Environment* env = Environment::GetCurrent(args);
DiffieHellman* diffieHellman =
new DiffieHellman(env, args.This());
bool initialized = false;
if (args.Length() == 2) { if (args.Length() != 2) {
if (args[0]->IsInt32()) { return THROW_ERR_MISSING_ARGS(env, "Constructor must have two arguments");
if (args[1]->IsInt32()) { }
initialized = diffieHellman->Init(args[0].As<Int32>()->Value(),
args[1].As<Int32>()->Value()); if (args[0]->IsInt32()) {
} int32_t bits = args[0].As<Int32>()->Value();
} else { if (bits < 2) {
ArrayBufferOrViewContents<char> arg0(args[0]); #if OPENSSL_VERSION_MAJOR >= 3
if (UNLIKELY(!arg0.CheckSizeInt32())) ERR_put_error(ERR_LIB_DH, 0, DH_R_MODULUS_TOO_SMALL, __FILE__, __LINE__);
return THROW_ERR_OUT_OF_RANGE(env, "prime is too big"); #else
if (args[1]->IsInt32()) { ERR_put_error(ERR_LIB_BN, 0, BN_R_BITS_TOO_SMALL, __FILE__, __LINE__);
initialized = diffieHellman->Init(arg0.data(), #endif
arg0.size(), return ThrowCryptoError(env, ERR_get_error(), "Invalid prime length");
args[1].As<Int32>()->Value()); }
} else {
ArrayBufferOrViewContents<char> arg1(args[1]); // If the first argument is an Int32 then we are generating a new
if (UNLIKELY(!arg1.CheckSizeInt32())) // prime and then using that to generate the Diffie-Hellman parameters.
return THROW_ERR_OUT_OF_RANGE(env, "generator is too big"); // The second argument must be an Int32 as well.
initialized = diffieHellman->Init(arg0.data(), arg0.size(), if (!args[1]->IsInt32()) {
arg1.data(), arg1.size()); return THROW_ERR_INVALID_ARG_TYPE(env,
} "Second argument must be an int32");
}
int32_t generator = args[1].As<Int32>()->Value();
if (generator < 2) {
ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__);
return ThrowCryptoError(env, ERR_get_error(), "Invalid generator");
}
auto dh = DHPointer::New(bits, generator);
if (!dh) {
return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid DH parameters");
}
new DiffieHellman(env, args.This(), std::move(dh));
return;
}
// The first argument must be an ArrayBuffer or ArrayBufferView with the
// prime, and the second argument must be an int32 with the generator
// or an ArrayBuffer or ArrayBufferView with the generator.
ArrayBufferOrViewContents<char> arg0(args[0]);
if (UNLIKELY(!arg0.CheckSizeInt32()))
return THROW_ERR_OUT_OF_RANGE(env, "prime is too big");
BignumPointer bn_p(reinterpret_cast<uint8_t*>(arg0.data()), arg0.size());
BignumPointer bn_g;
if (!bn_p) {
return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid prime");
}
if (args[1]->IsInt32()) {
int32_t generator = args[1].As<Int32>()->Value();
if (generator < 2) {
ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__);
return ThrowCryptoError(env, ERR_get_error(), "Invalid generator");
}
bn_g = BignumPointer::New();
if (!bn_g.setWord(generator)) {
ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__);
return ThrowCryptoError(env, ERR_get_error(), "Invalid generator");
}
} else {
ArrayBufferOrViewContents<char> arg1(args[1]);
if (UNLIKELY(!arg1.CheckSizeInt32()))
return THROW_ERR_OUT_OF_RANGE(env, "generator is too big");
bn_g = BignumPointer(reinterpret_cast<uint8_t*>(arg1.data()), arg1.size());
if (!bn_g) {
ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__);
return ThrowCryptoError(env, ERR_get_error(), "Invalid generator");
}
if (bn_g.getWord() < 2) {
ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__);
return ThrowCryptoError(env, ERR_get_error(), "Invalid generator");
} }
} }
if (!initialized) { auto dh = DHPointer::New(std::move(bn_p), std::move(bn_g));
return ThrowCryptoError(env, ERR_get_error(), "Initialization failed"); if (!dh) {
return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid DH parameters");
} }
new DiffieHellman(env, args.This(), std::move(dh));
} }
void GenerateKeys(const FunctionCallbackInfo<Value>& args) {
void DiffieHellman::GenerateKeys(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args); Environment* env = Environment::GetCurrent(args);
DiffieHellman* diffieHellman; DiffieHellman* diffieHellman;
ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This()); ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
DHPointer& dh = *diffieHellman;
if (!DH_generate_key(diffieHellman->dh_.get())) { auto dp = dh.generateKeys();
return ThrowCryptoError(env, ERR_get_error(), "Key generation failed"); if (!dp) {
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Key generation failed");
} }
const BIGNUM* pub_key;
DH_get0_key(diffieHellman->dh_.get(), &pub_key, nullptr);
std::unique_ptr<BackingStore> bs;
{
const int size = BignumPointer::GetByteCount(pub_key);
CHECK_GE(size, 0);
NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
bs = ArrayBuffer::NewBackingStore(env->isolate(), size);
}
CHECK_EQ(
bs->ByteLength(),
BignumPointer::EncodePaddedInto(
pub_key, static_cast<unsigned char*>(bs->Data()), bs->ByteLength()));
Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
Local<Value> buffer; Local<Value> buffer;
if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&buffer)) return; if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) {
args.GetReturnValue().Set(buffer); args.GetReturnValue().Set(buffer);
}
void DiffieHellman::GetField(const FunctionCallbackInfo<Value>& args,
const BIGNUM* (*get_field)(const DH*),
const char* err_if_null) {
Environment* env = Environment::GetCurrent(args);
DiffieHellman* dh;
ASSIGN_OR_RETURN_UNWRAP(&dh, args.This());
const BIGNUM* num = get_field(dh->dh_.get());
if (num == nullptr)
return THROW_ERR_CRYPTO_INVALID_STATE(env, err_if_null);
std::unique_ptr<BackingStore> bs;
{
const int size = BignumPointer::GetByteCount(num);
CHECK_GE(size, 0);
NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
bs = ArrayBuffer::NewBackingStore(env->isolate(), size);
} }
CHECK_EQ(bs->ByteLength(),
BignumPointer::EncodePaddedInto(
num, static_cast<unsigned char*>(bs->Data()), bs->ByteLength()));
Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
Local<Value> buffer;
if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&buffer)) return;
args.GetReturnValue().Set(buffer);
} }
void DiffieHellman::GetPrime(const FunctionCallbackInfo<Value>& args) { void GetPrime(const FunctionCallbackInfo<Value>& args) {
GetField(args, [](const DH* dh) -> const BIGNUM* {
const BIGNUM* p;
DH_get0_pqg(dh, &p, nullptr, nullptr);
return p;
}, "p is null");
}
void DiffieHellman::GetGenerator(const FunctionCallbackInfo<Value>& args) {
GetField(args, [](const DH* dh) -> const BIGNUM* {
const BIGNUM* g;
DH_get0_pqg(dh, nullptr, nullptr, &g);
return g;
}, "g is null");
}
void DiffieHellman::GetPublicKey(const FunctionCallbackInfo<Value>& args) {
GetField(args, [](const DH* dh) -> const BIGNUM* {
const BIGNUM* pub_key;
DH_get0_key(dh, &pub_key, nullptr);
return pub_key;
}, "No public key - did you forget to generate one?");
}
void DiffieHellman::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
GetField(args, [](const DH* dh) -> const BIGNUM* {
const BIGNUM* priv_key;
DH_get0_key(dh, nullptr, &priv_key);
return priv_key;
}, "No private key - did you forget to generate one?");
}
void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args); Environment* env = Environment::GetCurrent(args);
DiffieHellman* diffieHellman; DiffieHellman* diffieHellman;
ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This()); ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
DHPointer& dh = *diffieHellman;
ClearErrorOnReturn clear_error_on_return; auto dp = dh.getPrime();
if (!dp) {
return THROW_ERR_CRYPTO_INVALID_STATE(env, "p is null");
}
Local<Value> buffer;
if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) {
args.GetReturnValue().Set(buffer);
}
}
void GetGenerator(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
DiffieHellman* diffieHellman;
ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
DHPointer& dh = *diffieHellman;
auto dp = dh.getGenerator();
if (!dp) {
return THROW_ERR_CRYPTO_INVALID_STATE(env, "g is null");
}
Local<Value> buffer;
if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) {
args.GetReturnValue().Set(buffer);
}
}
void GetPublicKey(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
DiffieHellman* diffieHellman;
ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
DHPointer& dh = *diffieHellman;
auto dp = dh.getPublicKey();
if (!dp) {
return THROW_ERR_CRYPTO_INVALID_STATE(
env, "No public key - did you forget to generate one?");
}
Local<Value> buffer;
if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) {
args.GetReturnValue().Set(buffer);
}
}
void GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
DiffieHellman* diffieHellman;
ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
DHPointer& dh = *diffieHellman;
auto dp = dh.getPrivateKey();
if (!dp) {
return THROW_ERR_CRYPTO_INVALID_STATE(
env, "No private key - did you forget to generate one?");
}
Local<Value> buffer;
if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) {
args.GetReturnValue().Set(buffer);
}
}
void ComputeSecret(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
DiffieHellman* diffieHellman;
ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
DHPointer& dh = *diffieHellman;
CHECK_EQ(args.Length(), 1); CHECK_EQ(args.Length(), 1);
ArrayBufferOrViewContents<unsigned char> key_buf(args[0]); ArrayBufferOrViewContents<unsigned char> key_buf(args[0]);
@ -398,93 +257,72 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
return THROW_ERR_OUT_OF_RANGE(env, "secret is too big"); return THROW_ERR_OUT_OF_RANGE(env, "secret is too big");
BignumPointer key(key_buf.data(), key_buf.size()); BignumPointer key(key_buf.data(), key_buf.size());
std::unique_ptr<BackingStore> bs; switch (dh.checkPublicKey(key)) {
{ case DHPointer::CheckPublicKeyResult::INVALID:
NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data()); // Fall-through
bs = ArrayBuffer::NewBackingStore(env->isolate(), case DHPointer::CheckPublicKeyResult::CHECK_FAILED:
DH_size(diffieHellman->dh_.get())); return THROW_ERR_CRYPTO_INVALID_KEYTYPE(env,
"Unspecified validation error");
case DHPointer::CheckPublicKeyResult::TOO_SMALL:
return THROW_ERR_CRYPTO_INVALID_KEYLEN(env, "Supplied key is too small");
case DHPointer::CheckPublicKeyResult::TOO_LARGE:
return THROW_ERR_CRYPTO_INVALID_KEYLEN(env, "Supplied key is too large");
case DHPointer::CheckPublicKeyResult::NONE:
break;
} }
int size = DH_compute_key(static_cast<unsigned char*>(bs->Data()), auto dp = dh.computeSecret(key);
key.get(),
diffieHellman->dh_.get());
if (size == -1) {
int checkResult;
int checked;
checked = DH_check_pub_key(diffieHellman->dh_.get(),
key.get(),
&checkResult);
if (!checked) {
return ThrowCryptoError(env, ERR_get_error(), "Invalid Key");
} else if (checkResult) {
if (checkResult & DH_CHECK_PUBKEY_TOO_SMALL) {
return THROW_ERR_CRYPTO_INVALID_KEYLEN(env,
"Supplied key is too small");
} else if (checkResult & DH_CHECK_PUBKEY_TOO_LARGE) {
return THROW_ERR_CRYPTO_INVALID_KEYLEN(env,
"Supplied key is too large");
}
}
return THROW_ERR_CRYPTO_INVALID_KEYTYPE(env);
}
CHECK_GE(size, 0);
ZeroPadDiffieHellmanSecret(size,
static_cast<char*>(bs->Data()),
bs->ByteLength());
Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
Local<Value> buffer; Local<Value> buffer;
if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&buffer)) return; if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) {
args.GetReturnValue().Set(buffer); args.GetReturnValue().Set(buffer);
}
} }
void DiffieHellman::SetKey(const FunctionCallbackInfo<Value>& args, void SetPublicKey(const FunctionCallbackInfo<Value>& args) {
int (*set_field)(DH*, BIGNUM*), const char* what) {
Environment* env = Environment::GetCurrent(args); Environment* env = Environment::GetCurrent(args);
DiffieHellman* dh; DiffieHellman* diffieHellman;
ASSIGN_OR_RETURN_UNWRAP(&dh, args.This()); ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
DHPointer& dh = *diffieHellman;
CHECK_EQ(args.Length(), 1); CHECK_EQ(args.Length(), 1);
ArrayBufferOrViewContents<unsigned char> buf(args[0]); ArrayBufferOrViewContents<unsigned char> buf(args[0]);
if (UNLIKELY(!buf.CheckSizeInt32())) if (UNLIKELY(!buf.CheckSizeInt32()))
return THROW_ERR_OUT_OF_RANGE(env, "buf is too big"); return THROW_ERR_OUT_OF_RANGE(env, "buf is too big");
BignumPointer num(buf.data(), buf.size()); BignumPointer num(buf.data(), buf.size());
CHECK(num); CHECK(num);
CHECK_EQ(1, set_field(dh->dh_.get(), num.release())); CHECK(dh.setPublicKey(std::move(num)));
} }
void DiffieHellman::SetPublicKey(const FunctionCallbackInfo<Value>& args) { void SetPrivateKey(const FunctionCallbackInfo<Value>& args) {
SetKey(args, Environment* env = Environment::GetCurrent(args);
[](DH* dh, BIGNUM* num) { return DH_set0_key(dh, num, nullptr); }, DiffieHellman* diffieHellman;
"Public key"); ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
DHPointer& dh = *diffieHellman;
CHECK_EQ(args.Length(), 1);
ArrayBufferOrViewContents<unsigned char> buf(args[0]);
if (UNLIKELY(!buf.CheckSizeInt32()))
return THROW_ERR_OUT_OF_RANGE(env, "buf is too big");
BignumPointer num(buf.data(), buf.size());
CHECK(num);
CHECK(dh.setPrivateKey(std::move(num)));
} }
void DiffieHellman::SetPrivateKey(const FunctionCallbackInfo<Value>& args) { void Check(const FunctionCallbackInfo<Value>& args) {
SetKey(args, Environment* env = Environment::GetCurrent(args);
[](DH* dh, BIGNUM* num) { return DH_set0_key(dh, nullptr, num); },
"Private key");
}
void DiffieHellman::VerifyErrorGetter(const FunctionCallbackInfo<Value>& args) {
HandleScope scope(args.GetIsolate());
DiffieHellman* diffieHellman; DiffieHellman* diffieHellman;
ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This()); ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
args.GetReturnValue().Set(diffieHellman->verifyError_); DHPointer& dh = *diffieHellman;
auto result = dh.check();
if (result == DHPointer::CheckResult::CHECK_FAILED) {
return THROW_ERR_CRYPTO_OPERATION_FAILED(env,
"Checking DH parameters failed");
}
args.GetReturnValue().Set(static_cast<int>(result));
} }
bool DiffieHellman::VerifyContext() { } // namespace
int codes;
if (!DH_check(dh_.get(), &codes))
return false;
verifyError_ = codes;
return true;
}
// The input arguments to DhKeyPairGenJob can vary // The input arguments to DhKeyPairGenJob can vary
// 1. CryptoJobMode // 1. CryptoJobMode
@ -509,13 +347,15 @@ Maybe<bool> DhKeyGenTraits::AdditionalConfig(
if (args[*offset]->IsString()) { if (args[*offset]->IsString()) {
Utf8Value group_name(env->isolate(), args[*offset]); Utf8Value group_name(env->isolate(), args[*offset]);
auto group = FindDiffieHellmanGroup(*group_name); auto group = DHPointer::FindGroup(group_name.ToStringView());
if (group == nullptr) { if (!group) {
THROW_ERR_CRYPTO_UNKNOWN_DH_GROUP(env); THROW_ERR_CRYPTO_UNKNOWN_DH_GROUP(env);
return Nothing<bool>(); return Nothing<bool>();
} }
params->params.prime = group(); static constexpr int kStandardizedGenerator = 2;
params->params.prime = std::move(group);
params->params.generator = kStandardizedGenerator; params->params.generator = kStandardizedGenerator;
*offset += 1; *offset += 1;
} else { } else {
@ -547,15 +387,13 @@ EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) {
EVPKeyPointer key_params; EVPKeyPointer key_params;
if (BignumPointer* prime_fixed_value = if (BignumPointer* prime_fixed_value =
std::get_if<BignumPointer>(&params->params.prime)) { std::get_if<BignumPointer>(&params->params.prime)) {
DHPointer dh(DH_new()); auto prime = prime_fixed_value->clone();
if (!dh)
return EVPKeyCtxPointer();
auto bn_g = BignumPointer::New(); auto bn_g = BignumPointer::New();
if (!bn_g.setWord(params->params.generator) || if (!prime || !bn_g || !bn_g.setWord(params->params.generator)) {
!SetDhParams(dh.get(), prime_fixed_value, &bn_g)) { return {};
return EVPKeyCtxPointer();
} }
auto dh = DHPointer::New(std::move(prime), std::move(bn_g));
if (!dh) return {};
key_params = EVPKeyPointer(EVP_PKEY_new()); key_params = EVPKeyPointer(EVP_PKEY_new());
CHECK(key_params); CHECK(key_params);
@ -572,7 +410,7 @@ EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) {
param_ctx.get(), param_ctx.get(),
params->params.generator) <= 0 || params->params.generator) <= 0 ||
EVP_PKEY_paramgen(param_ctx.get(), &raw_params) <= 0) { EVP_PKEY_paramgen(param_ctx.get(), &raw_params) <= 0) {
return EVPKeyCtxPointer(); return {};
} }
key_params = EVPKeyPointer(raw_params); key_params = EVPKeyPointer(raw_params);
@ -581,8 +419,7 @@ EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) {
} }
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(key_params.get(), nullptr)); EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(key_params.get(), nullptr));
if (!ctx || EVP_PKEY_keygen_init(ctx.get()) <= 0) if (!ctx || EVP_PKEY_keygen_init(ctx.get()) <= 0) return {};
return EVPKeyCtxPointer();
return ctx; return ctx;
} }
@ -616,29 +453,15 @@ WebCryptoKeyExportStatus DHKeyExportTraits::DoExport(
} }
namespace { namespace {
ByteSource StatelessDiffieHellmanThreadsafe( ByteSource StatelessDiffieHellmanThreadsafe(const ManagedEVPPKey& our_key,
const ManagedEVPPKey& our_key, const ManagedEVPPKey& their_key) {
const ManagedEVPPKey& their_key) { auto dp = DHPointer::stateless(our_key.pkey(), their_key.pkey());
size_t out_size; if (!dp) return {};
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(our_key.get(), nullptr)); return ByteSource::Allocated(dp.release());
if (!ctx ||
EVP_PKEY_derive_init(ctx.get()) <= 0 ||
EVP_PKEY_derive_set_peer(ctx.get(), their_key.get()) <= 0 ||
EVP_PKEY_derive(ctx.get(), nullptr, &out_size) <= 0)
return ByteSource();
ByteSource::Builder out(out_size);
if (EVP_PKEY_derive(ctx.get(), out.data<unsigned char>(), &out_size) <= 0) {
return ByteSource();
}
ZeroPadDiffieHellmanSecret(out_size, out.data<char>(), out.size());
return std::move(out).release();
} }
} // namespace
void DiffieHellman::Stateless(const FunctionCallbackInfo<Value>& args) { void Stateless(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args); Environment* env = Environment::GetCurrent(args);
CHECK(args[0]->IsObject() && args[1]->IsObject()); CHECK(args[0]->IsObject() && args[1]->IsObject());
@ -662,6 +485,7 @@ void DiffieHellman::Stateless(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(out); args.GetReturnValue().Set(out);
} }
} // namespace
Maybe<bool> DHBitsTraits::AdditionalConfig( Maybe<bool> DHBitsTraits::AdditionalConfig(
CryptoJobMode mode, CryptoJobMode mode,
@ -719,5 +543,75 @@ Maybe<bool> GetDhKeyDetail(
return Just(true); return Just(true);
} }
void DiffieHellman::Initialize(Environment* env, Local<Object> target) {
Isolate* isolate = env->isolate();
Local<Context> context = env->context();
auto make = [&](Local<String> name, FunctionCallback callback) {
Local<FunctionTemplate> t = NewFunctionTemplate(isolate, callback);
const PropertyAttribute attributes =
static_cast<PropertyAttribute>(ReadOnly | DontDelete);
t->InstanceTemplate()->SetInternalFieldCount(
DiffieHellman::kInternalFieldCount);
SetProtoMethod(isolate, t, "generateKeys", GenerateKeys);
SetProtoMethod(isolate, t, "computeSecret", ComputeSecret);
SetProtoMethodNoSideEffect(isolate, t, "getPrime", GetPrime);
SetProtoMethodNoSideEffect(isolate, t, "getGenerator", GetGenerator);
SetProtoMethodNoSideEffect(isolate, t, "getPublicKey", GetPublicKey);
SetProtoMethodNoSideEffect(isolate, t, "getPrivateKey", GetPrivateKey);
SetProtoMethod(isolate, t, "setPublicKey", SetPublicKey);
SetProtoMethod(isolate, t, "setPrivateKey", SetPrivateKey);
Local<FunctionTemplate> verify_error_getter_templ =
FunctionTemplate::New(isolate,
Check,
Local<Value>(),
Signature::New(env->isolate(), t),
/* length */ 0,
ConstructorBehavior::kThrow,
SideEffectType::kHasNoSideEffect);
t->InstanceTemplate()->SetAccessorProperty(env->verify_error_string(),
verify_error_getter_templ,
Local<FunctionTemplate>(),
attributes);
SetConstructorFunction(context, target, name, t);
};
make(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellman"), New);
make(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellmanGroup"),
DiffieHellmanGroup);
SetMethodNoSideEffect(context, target, "statelessDH", Stateless);
DHKeyPairGenJob::Initialize(env, target);
DHKeyExportJob::Initialize(env, target);
DHBitsJob::Initialize(env, target);
}
void DiffieHellman::RegisterExternalReferences(
ExternalReferenceRegistry* registry) {
registry->Register(New);
registry->Register(DiffieHellmanGroup);
registry->Register(GenerateKeys);
registry->Register(ComputeSecret);
registry->Register(GetPrime);
registry->Register(GetGenerator);
registry->Register(GetPublicKey);
registry->Register(GetPrivateKey);
registry->Register(SetPublicKey);
registry->Register(SetPrivateKey);
registry->Register(Check);
registry->Register(Stateless);
DHKeyPairGenJob::RegisterExternalReferences(registry);
DHKeyExportJob::RegisterExternalReferences(registry);
DHBitsJob::RegisterExternalReferences(registry);
}
} // namespace crypto } // namespace crypto
} // namespace node } // namespace node

View File

@ -14,48 +14,19 @@
namespace node { namespace node {
namespace crypto { namespace crypto {
class DiffieHellman : public BaseObject { class DiffieHellman final : public BaseObject {
public: public:
static void Initialize(Environment* env, v8::Local<v8::Object> target); static void Initialize(Environment* env, v8::Local<v8::Object> target);
static void RegisterExternalReferences(ExternalReferenceRegistry* registry); static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
bool Init(int primeLength, int g); DiffieHellman(Environment* env, v8::Local<v8::Object> wrap, DHPointer dh);
bool Init(BignumPointer&& bn_p, int g); operator DHPointer&() { return dh_; }
bool Init(const char* p, int p_len, int g);
bool Init(const char* p, int p_len, const char* g, int g_len);
static void Stateless(const v8::FunctionCallbackInfo<v8::Value>& args);
protected:
static void DiffieHellmanGroup(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GenerateKeys(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetPrime(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetGenerator(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetPublicKey(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetPrivateKey(const v8::FunctionCallbackInfo<v8::Value>& args);
static void ComputeSecret(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetPublicKey(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetPrivateKey(const v8::FunctionCallbackInfo<v8::Value>& args);
static void VerifyErrorGetter(
const v8::FunctionCallbackInfo<v8::Value>& args);
DiffieHellman(Environment* env, v8::Local<v8::Object> wrap);
void MemoryInfo(MemoryTracker* tracker) const override; void MemoryInfo(MemoryTracker* tracker) const override;
SET_MEMORY_INFO_NAME(DiffieHellman) SET_MEMORY_INFO_NAME(DiffieHellman)
SET_SELF_SIZE(DiffieHellman) SET_SELF_SIZE(DiffieHellman)
private: private:
static void GetField(const v8::FunctionCallbackInfo<v8::Value>& args,
const BIGNUM* (*get_field)(const DH*),
const char* err_if_null);
static void SetKey(const v8::FunctionCallbackInfo<v8::Value>& args,
int (*set_field)(DH*, BIGNUM*), const char* what);
bool VerifyContext();
int verifyError_;
DHPointer dh_; DHPointer dh_;
}; };

View File

@ -92,7 +92,7 @@ const crypto = require('crypto');
assert.throws(() => { assert.throws(() => {
dh3.computeSecret(''); dh3.computeSecret('');
}, { message: common.hasOpenSSL3 && !hasOpenSSL3WithNewErrorMessage ? }, { message: common.hasOpenSSL3 && !hasOpenSSL3WithNewErrorMessage ?
'error:02800080:Diffie-Hellman routines::invalid secret' : 'Unspecified validation error' :
'Supplied key is too small' }); 'Supplied key is too small' });
} }
} }