我正在为嵌入式Linux设备添加HTTPS支持。我已尝试使用以下步骤生成自签名证书:

openssl req -new > cert.csr
openssl rsa -in privkey.pem -out key.pem
openssl x509 -in cert.csr -out cert.pem -req -signkey key.pem -days 1001
cat key.pem>>cert.pem

这是可行的,但我在Google Chrome上遇到了一些错误:

这可能不是你要找的网站!站点的安全证书不受信任!

我错过了什么吗?这是构建自签名证书的正确方法吗?


当前回答

这对我有用

openssl req -x509 -nodes -subj '/CN=localhost'  -newkey rsa:4096 -keyout ./sslcert/key.pem -out ./sslcert/cert.pem -days 365

服务器.js

var fs = require('fs');
var path = require('path');
var http = require('http');
var https = require('https');
var compression = require('compression');
var express = require('express');
var app = express();

app.use(compression());
app.use(express.static(__dirname + '/www'));    

app.get('/*', function(req,res) {
  res.sendFile(path.join(__dirname+'/www/index.html'));
});

// your express configuration here

var httpServer = http.createServer(app);
var credentials = {
    key: fs.readFileSync('./sslcert/key.pem', 'utf8'),
    cert: fs.readFileSync('./sslcert/cert.pem', 'utf8')
};
var httpsServer = https.createServer(credentials, app);

httpServer.listen(8080);
httpsServer.listen(8443);

console.log(`RUNNING ON  http://127.0.0.1:8080`);
console.log(`RUNNING ON  http://127.0.0.1:8443`);

其他回答

这个非常简单的Python应用程序创建了一个自签名证书。代码:

from OpenSSL import crypto, SSL
from secrets import randbelow
print("Please know, if you make a mistake, you must restart the program.")
def cert_gen(
    emailAddress=input("Enter Email Address: "),
    commonName=input("Enter Common Name: "),
    countryName=input("Enter Country Name (2 characters): "),
    localityName=input("Enter Locality Name: "),
    stateOrProvinceName=input("Enter State of Province Name: "),
    organizationName=input("Enter Organization Name: "),
    organizationUnitName=input("Enter Organization Unit Name: "),
    serialNumber=randbelow(1000000),
    validityStartInSeconds=0,
    validityEndInSeconds=10*365*24*60*60,
    KEY_FILE = "private.key",
    CERT_FILE="selfsigned.crt"):
    #can look at generated file using openssl:
    #openssl x509 -inform pem -in selfsigned.crt -noout -text
    # create a key pair
    k = crypto.PKey()
    k.generate_key(crypto.TYPE_RSA, 4096)
    # create a self-signed cert
    cert = crypto.X509()
    cert.get_subject().C = countryName
    cert.get_subject().ST = stateOrProvinceName
    cert.get_subject().L = localityName
    cert.get_subject().O = organizationName
    cert.get_subject().OU = organizationUnitName
    cert.get_subject().CN = commonName
    cert.get_subject().emailAddress = emailAddress
    cert.set_serial_number(serialNumber)
    cert.gmtime_adj_notBefore(0)
    cert.gmtime_adj_notAfter(validityEndInSeconds)
    cert.set_issuer(cert.get_subject())
    cert.set_pubkey(k)
    cert.sign(k, 'sha512')
    with open(CERT_FILE, "wt") as f:
        f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode("utf-8"))
    with open(KEY_FILE, "wt") as f:
        f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k).decode("utf-8"))
    print("GENERATED")
    input("Press enter to close program.")
cert_gen()

但是,您仍然会收到“证书不受信任”错误。这是因为以下几个原因:

它是自签名/未验证的(验证的证书需要CA(证书颁发机构),如Let's Encrypt,以便在所有设备上都受信任)。您的计算机上不信任它。(此答案显示了如何使Windows信任您的证书)。

从2023年起,OpenSSL≥1.1.1,以下命令可满足您的所有需求,包括主题备用名称(SAN):

openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
  -keyout example.key -out example.crt -subj "/CN=example.com" \
  -addext "subjectAltName=DNS:example.com,DNS:www.example.net,IP:10.0.0.1"

在OpenSSL≤1.1.0的旧系统上,如Debian≤9或CentOS≤7,需要使用此命令的更长版本:

openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
  -keyout example.key -out example.crt -extensions san -config \
  <(echo "[req]"; 
    echo distinguished_name=req; 
    echo "[san]"; 
    echo subjectAltName=DNS:example.com,DNS:www.example.net,IP:10.0.0.1
    ) \
  -subj "/CN=example.com"

任一命令都创建一个证书

对于(子)域example.com和www.example.net(SAN)有效,对于IP地址10.0.0.1(SAN)也是有效的,相对强劲(截至2023年)有效期为3650天(约10年)。

将生成以下文件:

私钥:example.key证书:example.crt

所有信息都在命令行中提供。没有让你烦恼的互动输入。没有你必须处理的配置文件。所有必要的步骤都由单个OpenSSL调用执行:从私钥生成到自签名证书。


备注#1:加密参数

由于证书是自签名的,需要用户手动接受,因此使用短到期或弱加密是没有意义的。

未来,您可能希望使用超过4096位的RSA密钥和比sha256更强的哈希算法,但截至2023年,这些都是正常的值。它们足够强大,同时受到所有现代浏览器的支持。

备注#2:参数“-nodes”

理论上,您可以省略-nodes参数(这意味着“没有DES加密”),在这种情况下,example.key将使用密码进行加密。然而,这对于服务器安装几乎从来都没有用处,因为您要么必须将密码也存储在服务器上,要么必须在每次重新启动时手动输入密码。

备注#3:另请参见

直接在命令行上向openssl提供subjectAltName如何通过命令行向SSL证书添加多个电子邮件地址?有关MSYS_NO_PATHCONV的更多信息

这是我在本地箱上使用的脚本,用于在自签名证书中设置SAN(subjectAltName)。

此脚本采用域名(example.com)并在同一证书中为*.example.com和example.com生成SAN。对以下各节进行了评论。为脚本命名(例如generatessl.sh)并赋予其可执行权限。文件将被写入与脚本相同的目录。

Chrome 58及更高版本要求在自签名证书中设置SAN。

#!/usr/bin/env bash

# Set the TLD domain we want to use
BASE_DOMAIN="example.com"

# Days for the cert to live
DAYS=1095

# A blank passphrase
PASSPHRASE=""

# Generated configuration file
CONFIG_FILE="config.txt"

cat > $CONFIG_FILE <<-EOF
[req]
default_bits = 2048
prompt = no
default_md = sha256
x509_extensions = v3_req
distinguished_name = dn

[dn]
C = CA
ST = BC
L = Vancouver
O = Example Corp
OU = Testing Domain
emailAddress = webmaster@$BASE_DOMAIN
CN = $BASE_DOMAIN

[v3_req]
subjectAltName = @alt_names

[alt_names]
DNS.1 = *.$BASE_DOMAIN
DNS.2 = $BASE_DOMAIN
EOF

# The file name can be anything
FILE_NAME="$BASE_DOMAIN"

# Remove previous keys
echo "Removing existing certs like $FILE_NAME.*"
chmod 770 $FILE_NAME.*
rm $FILE_NAME.*

echo "Generating certs for $BASE_DOMAIN"

# Generate our Private Key, CSR and Certificate
# Use SHA-2 as SHA-1 is unsupported from Jan 1, 2017

openssl req -new -x509 -newkey rsa:2048 -sha256 -nodes -keyout "$FILE_NAME.key" -days $DAYS -out "$FILE_NAME.crt" -passin pass:$PASSPHRASE -config "$CONFIG_FILE"

# OPTIONAL - write an info to see the details of the generated crt
openssl x509 -noout -fingerprint -text < "$FILE_NAME.crt" > "$FILE_NAME.info"

# Protect the key
chmod 400 "$FILE_NAME.key"

该脚本还编写了一个信息文件,因此您可以检查新证书并验证SAN设置是否正确。

                ...
                28:dd:b8:1e:34:b5:b1:44:1a:60:6d:e3:3c:5a:c4:
                da:3d
            Exponent: 65537 (0x10001)
    X509v3 extensions:
        X509v3 Subject Alternative Name: 
            DNS:*.example.com, DNS:example.com
Signature Algorithm: sha256WithRSAEncryption
     3b:35:5a:d6:9e:92:4f:fc:f4:f4:87:78:cd:c7:8d:cd:8c:cc:
     ...

如果您使用的是Apache,则可以在配置文件中引用上述证书,如下所示:

<VirtualHost _default_:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/htdocs

    SSLEngine on
    SSLCertificateFile path/to/your/example.com.crt
    SSLCertificateKeyFile path/to/your/example.com.key
</VirtualHost>

请记住重新启动Apache(或Nginx或IIS)服务器以使新证书生效。

2017年一艘班轮:

openssl req \
-newkey rsa:2048 \
-x509 \
-nodes \
-keyout server.pem \
-new \
-out server.pem \
-subj /CN=localhost \
-reqexts SAN \
-extensions SAN \
-config <(cat /System/Library/OpenSSL/openssl.cnf \
    <(printf '[SAN]\nsubjectAltName=DNS:localhost')) \
-sha256 \
-days 3650

这也适用于Chrome 57,因为它提供了SAN,而无需另一个配置文件。它取自这里的一个答案。

这将创建一个包含私钥和证书的.pem文件。如果需要,可以将它们移动到单独的.pem。

我建议添加-sha256参数,以使用SHA-2哈希算法,因为主要浏览器正在考虑将“SHA-1证书”显示为不安全。

来自已接受答案的同一命令行-@diegows,添加了-sha256

openssl req-x509-sha256-newkey rsa:2048-keyout key.pem-out cert.pem-天XXX

更多信息请访问谷歌安全博客。

2018年5月更新。正如许多人在评论中指出的那样,使用SHA-2不会为自签名证书添加任何安全性。但我仍然建议使用它作为一个好习惯,不要使用过时/不安全的加密哈希函数。在“为什么最终实体证书之上的证书可以基于SHA-1?”中提供了完整的解释?。