我正在为嵌入式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上遇到了一些错误:

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

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


当前回答

这是我在本地箱上使用的脚本,用于在自签名证书中设置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)服务器以使新证书生效。

其他回答

这对我有用

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`);

以下是@diegows的答案中描述的选项,在文档中有更详细的描述:

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

请求PKCS#10证书请求和证书生成实用程序。-2009年5月此选项输出自签名证书,而不是证书请求。这通常用于生成测试证书或自签名根CA。-新密钥参数此选项创建新的证书请求和新的私钥。争论采取多种形式之一。rsa:nbits,其中nbits是位数,生成大小为n位的RSA密钥。-键入文件名这提供了用于写入新创建的私钥的文件名。-输出文件名默认情况下,指定要写入的输出文件名或标准输出。-第n天当使用-x509选项时,指定要验证的天数的证书。默认值为30天。-节点如果指定了此选项,则如果创建了私钥,则不会对其进行加密。

文件实际上比上述更详细;我只是在这里总结了一下。

这是我在本地箱上使用的脚本,用于在自签名证书中设置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)服务器以使新证书生效。

正如已经详细讨论过的,自签名证书不受Internet信任。您可以将自签名证书添加到许多浏览器,但不是所有浏览器。或者,您可以成为自己的证书颁发机构。

人们不想从证书颁发机构获得签名证书的主要原因是成本--赛门铁克每年收取995美元至1999美元的证书费用--仅针对用于内部网络的证书,赛门铁克每年收取399美元。如果您正在处理信用卡付款或为高利润公司的利润中心工作,那么该成本很容易被证明是合理的。对于一个在互联网上创建的个人项目,或者一个以最低预算运行的非营利组织,或者如果一个人在一个组织的成本中心工作,成本中心总是试图用更少的钱做更多的事情,这是很多人都无法承受的。

另一种方法是使用certbot(参见certbot)。Certbot是一个易于使用的自动客户端,可为web服务器获取和部署SSL/TLS证书。

如果您设置了certbot,则可以使其为您创建和维护Let's Encrypt证书颁发机构颁发的证书。

我在周末为我的组织做了这件事。我在服务器(Ubuntu 16.04)上安装了certbot所需的软件包,然后运行了设置和启用certbot所必需的命令。一个可能需要certbot的DNS插件-我们目前正在使用DigitalOcean,但可能很快会迁移到另一个服务。

请注意,有些指示不太正确,需要谷歌花点时间才能弄清楚。这第一次花了我相当多的时间,但现在我想我可以在几分钟内完成。

对于DigitalOcean,我遇到的一个问题是,系统提示我输入DigitalOcean凭据INI文件的路径。脚本所指的是应用程序和API页面以及该页面上的令牌/密钥选项卡。您需要为DigitalOcean的API创建或生成个人访问令牌(读写)——这是一个65个字符的十六进制字符串。然后需要将该字符串放入运行certbot的Web服务器上的文件中。该文件的第一行可以是注释(注释以#开头)。第二行是:

dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff

一旦我知道了如何为DigitalOcean的API设置读写令牌,就可以很容易地使用certbot来设置通配符证书。请注意,您不必设置通配符证书,而是可以指定要应用证书的每个域和子域。正是通配符证书需要包含来自DigitalOcean的个人访问令牌的凭据INI文件。

请注意,公钥证书(也称为身份证书或SSL证书)过期并需要续订。因此,您需要定期(重复)更新证书。certbot文档包括续订证书。

我的计划是编写一个脚本,使用openssl命令获取证书的到期日期,并在到期前30天或更短的时间内触发续订。然后我将把这个脚本添加到cron中,并每天运行一次。

以下是读取证书过期日期的命令:

root@prod-host:~# /usr/bin/openssl x509 -enddate -noout -in path-to-certificate-pem-file
notAfter=May 25 19:24:12 2019 GMT

这个非常简单的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信任您的证书)。