【发布时间】:2019-10-15 09:13:03
【问题描述】:
我正在尝试在 node.js 中使用 TLS 设置服务器和一些客户端。我在客户端和服务器上使用自签名证书。服务器运行正常,但是当我尝试连接客户端时,客户端出现以下错误:
Error: DEPTH_ZERO_SELF_SIGNED_CERT
证书生成
CA 证书:
# Create key to sign our own certs. Act like as our own a CA.
echo "SecuresPassphrase" > ./tls/passphrase.txt
openssl ecparam -name secp521r1 -genkey -noout -out ./tls/certs/ca/ca.plain.key # Generate private key
openssl pkcs8 -topk8 -passout file:./tls/passphrase.txt -in ./tls/certs/ca/ca.plain.key -out ./tls/certs/ca/ca.key # Generate encrypted private key
rm ./tls/certs/ca/ca.plain.key; # Remove unencrypted private key
# Generate CA cert
openssl req -config ./openssl/oid_file -passin file:./tls/passphrase.txt -new -x509 -days 365 -key ./tls/certs/ca/ca.key -out ./tls/certs/ca/ca.crt
服务器证书:
openssl ecparam -name secp521r1 -genkey -noout -out ./tls/certs/servers/server.key # Generate server private key
openssl req -config ./openssl/oid_file -new -key ./tls/certs/servers/server.key -out ./tls/certs/servers/server.csr # Generate signing request
openssl x509 -passin file:./tls/passphrase.txt -req -days 365 -in ./tls/certs/servers/server.csr -CA ./tls/certs/ca/ca.crt -CAkey ./tls/certs/ca/ca.key -CAcreateserial -out ./tls/server.crt
mv ./tls/server.crt ./tls/certs/servers/
客户证书:
客户端的证书是在 bash 循环中创建的,变量 ${name} 包含客户端的名称,并且每次迭代都会更改。
openssl ecparam -name secp521r1 -genkey -noout -out ./tls/certs/clients/${name}/client.key
openssl req -config ./openssl/oid_file -new -key ./tls/certs/clients/${name}/client.key -out ./tls/certs/clients/${name}/client.csr
openssl x509 -passin file:./tls/passphrase.txt -req -days 365 -in ./tls/certs/clients/${name}/client.csr -CA ./tls/certs/ca/ca.crt -CAkey ./tls/certs/ca/ca.key -CAcreateserial -out ./tls/client.crt
mv ./tls/client.crt ./tls/certs/clients/${name}/
我还尝试通过使用短暂的 Diffie-Hellman 交换来使用完美前向保密。客户端和服务器的参数创建为openssl dhparam -outform PEM -out ./tls/params/servers/server/dhparams.pem 2048
服务器代码:
return new Promise(resolve => {
// Define parameters of TLS socket
const options = {
rejectUnauthorized: false,
requestCert: true,
// Secure Context Parameters
ca: [fs.readFileSync("tls/certs/ca/ca.crt")],
cert: fs.readFileSync("tls/certs/servers/server.crt"),
key: fs.readFileSync("tls/certs/servers/server.key"),
ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:!RC4:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!SRP:!CAMELLIA",
dhparam: fs.readFileSync("tls/params/servers/server/dhparams.pem"),
ecdhCurve: tls.DEFAULT_ECDH_CURVE,
minVersion: "TLSv1.2"
};
// Iniciar servidor TLS
this.SERVIDOR = tls.createServer(options, function (socket) {
console.log("Server created.");
});
this.SERVIDOR.listen(this.puerto, this.direccion, function () {
console.log("Listening");
});
this.SERVIDOR.on("secureConnection", (socket) => this.handleRequest(socket));
this.SERVIDOR.on("tlsClientError", (error) => console.log("Error client TLs. %s", error));
});
客户代码:
return new Promise(resolve => {
// Define parameters of TLS socket
const options = {
host: this.NODE,
port: this.NODE_PORT,
rejectUnauthorized: false,
secureContext: tls.createSecureContext({
ca: [fs.readFileSync("tls/certs/ca/ca.crt")],
cert: fs.readFileSync("tls/certs/clients/" + this.NAME + "/client.crt"),
key: fs.readFileSync("tls/certs/clients/" + this.NAME + "/client.key"),
ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:!RC4:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!SRP:!CAMELLIA",
dhparam: fs.readFileSync("tls/params/clients/" + this.NAME + "/dhparams.pem"),
ecdhCurve: tls.DEFAULT_ECDH_CURVE,
minVersion: "TLSv1.2"
})
};
// Initialize TLS socket
this.WEB_SOCKET = tls.connect(options, function () {
// Check if TLS auth worked
if (this.authorized) {
console.log("Connection authorized by a Cert. Authority ");
} else {
console.log("Authorization not granted. Error: " + this.authorizationError);
}
});
我尝试过的:
- 将rejectUnauthorized 设置为
false。 - 尝试使用
NODE_TLS_REJECT_UNAUTHORIZED = "0";运行代码。它不起作用,我认为这不是生产的好选择。 - 检查了关于 SO,this one 的类似问题,它看起来与我的问题非常相似。但最受好评的答案来自 2014 年,我在 docs 上找不到太多关于杰出名称的信息。
- 我使用
openssl x509 -in *.cert -text检查了证书,它们看起来不错。
¿我是否错误地生成了证书?任何帮助表示赞赏。 谢谢!
编辑。 2019 年 16 月 10 日
代码有问题,当套接字启动时我没有使用resolve();。同样的问题仍然存在... 但是 尽管客户端出现授权错误,但服务器会触发“secureConnection”事件并交换消息。 ¿ 这有意义吗? *是的,这是有道理的,因为服务器接受未经授权的连接。如果我将服务器设置为拒绝未经认证的连接,则客户端会挂断 *
【问题讨论】:
-
与你的 Q 无关,但你的 dhparams 没用。您只启用了一个 (TLS1.2) 密码套件,它不使用 DHE;它确实使用 ecdhCurve,但将其设置为默认值与不设置它相同。即使您启用了其他密码套件,也没有将 DHE 与 EC 证书(和静态密钥)一起使用。对于 TLS1.3,如果您的系统(全部)支持它,则可以将 DHE 与 EC 证书一起使用,但只能用于标准组,而不是您生成的组。并且没有 TLS 客户端(任何版本)使用自己的临时参数。
-
@dave_thompson_085 非常感谢您提供的信息。我不知道。我会做出改变。有关在何处阅读有关这些问题的任何指针或建议。我发现 openssl 官方文档有时有点含糊。
-
@dave_thompson_085 关于您评论的这一部分“并且没有 TLS 客户端(任何版本)曾经使用它自己的临时参数。”我知道我不应该提供 dhparams 属性。但是在 nodejs 官方文档中关于 TLS 包,他们声明如下:“要使用带有 tls 模块的 DHE 使用 Perfect Forward Secrecy,需要生成 Diffie-Hellman 参数并使用 tls.createSecureContext() 的 dhparam 选项指定它们。以下说明使用用于生成此类参数的 OpenSSL 命令行界面..."。我应该提供我自己的 eph 吗?参数与否?
-
如果使用DHE(你不是)并且不是 TLS1.3,那么你需要在上配置dhparam服务器,但不是客户端;他们的医生对此并不清楚。从技术上讲,您不需要需要生成自己的参数,您可以使用来自另一个可信赖来源的参数——但在实践中评估这样的来源通常比仅仅生成新的更难参数。在不需要的地方提供它们并没有危害,比如客户端,只是没有好处。 ...
-
... 虽然我在这里,但最后一段(在 v11 中)也是错误的;它说“所有 TLSv1.3 套件都使用 ECDHE”。 1.3 中的第一个 keyexchange 不再在套件中;第二个和更实质性的 1.3 放弃了以前的静态 RSA 密钥交换并强制 PFS,但对于新的/未恢复的会话,它使用 either ECHDE 或 DHE(后者使用标准化组而不是可定制组,因此不需要配置)。
标签: node.js ssl openssl certificate tls1.2