当前位置: 首页 > article >正文

自签名CA证书

自定义实现一个CA(证书颁发机构)并且手动管理每个客户端证书

1. 创建自定义CA

首先,我们需要创建一个自定义的CA,并使用该CA来签署客户端证书。

1.1 生成CA的私钥和证书
# 生成CA的私钥
openssl genrsa -out ca.key 2048

# 生成CA的自签名证书
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt

1.2 配置CA的配置文件

创建一个 openssl.cnf 文件,用于定义CA的配置。以下是一个简单的配置示例:

[ req ]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn

[ dn ]
C = US
ST = California
L = San Francisco
O = My Organization
OU = IT
CN = My CA

[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = critical,CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

这个配置文件是用于配置 openssl 工具的 req 命令的参数,主要用于生成证书请求(Certificate Signing Request, CSR)或自签名证书。它定义了证书请求或生成证书时的默认参数和扩展属性(如 v3_ca 部分)。将 prompt 设置为 yes,这样在生成证书请求时,openssl 会提示你输入 DN(识别名)的信息下面是对这个配置文件中各个部分的具体解释:


[ req ] 部分

[ req ]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
  • default_bits:

    • 定义了生成私钥时默认的密钥长度(这里是 2048 位)。
    • 常见的密钥长度有 2048、4096 等。
  • prompt:

    • 设置为 no,表示生成证书请求时不会提示用户输入信息,而是直接使用配置文件中 dn 部分的内容。
  • default_md:

    • 指定默认的哈希算法,这里使用的是 SHA-256。
    • 其他可选的哈希算法包括 SHA-1、SHA-512 等。
  • distinguished_name:

    • 指定证书请求或证书中的 Distinguished Name(DN,识别名)的配置部分。
    • 这里指向了 [ dn ] 部分。

2. 生成客户端证书

现在,我们将为每个客户端生成一个私钥和证书请求,然后使用CA来签署这些证书。

2.1 生成客户端的私钥和证书请求
# 生成客户端1的私钥
openssl genrsa -out client1.key 2048

# 生成客户端1的证书请求
openssl req -new -key client1.key -out client1.csr -config openssl.cnf

2.2 使用CA签署客户端证书
# 使用CA签署客户端1的证书
openssl x509 -req -in client1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client1.crt -days 365 -sha256

重复上述步骤,为每个客户端生成相应的证书。

3. 在服务器端加载CA证书并验证客户端证书

现在,我们回到服务器端,加载CA证书,并在客户端连接时验证其证书。

3.1 配置服务器

在服务器端,你只需要加载CA的证书(ca.crt),而不是每个客户端的证书。这样,服务器会信任所有由该CA签发的客户端证书。

void setupServer(QSslServer *server) {
    // 加载服务器证书和私钥
    QFile serverCertFile("server_cert.pem");
    QFile serverKeyFile("server_key.pem");
    serverCertFile.open(QFile::ReadOnly);
    serverKeyFile.open(QFile::ReadOnly);
    QSslCertificate serverCert(&serverCertFile, QSsl::Pem);
    QSslKey serverKey(&serverKeyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, "your_password");

    // 加载CA的证书
    QFile caCertFile("ca.crt");
    caCertFile.open(QFile::ReadOnly);
    QSslCertificate caCert(&caCertFile, QSsl::Pem);

    // 配置SSL配置
    QSslConfiguration sslConfig = server->sslConfiguration();
    sslConfig.setLocalCertificate(serverCert);
    sslConfig.setPrivateKey(serverKey);
    sslConfig.setCaCertificates({caCert});  // 只需要加载CA的证书
    sslConfig.setPeerVerifyMode(QSslSocket::VerifyPeer);
    server->setSslConfiguration(sslConfig);

    // 连接信号槽
    connect(server, &QSslServer::newConnection, this, &YourClass::onNewConnection);
}

4. 验证客户端证书并标记客户端

在客户端连接时,验证其证书,并根据其 Common Name 进行标记。

void onNewConnection() {
    QSslSocket *clientSocket = server->nextPendingConnection();

    // 设置SSL配置
    QSslConfiguration sslConfig = clientSocket->sslConfiguration();
    sslConfig.setPeerVerifyMode(QSslSocket::VerifyPeer);
    clientSocket->setSslConfiguration(sslConfig);

    // 开始SSL握手
    clientSocket->startServerEncryption();

    // 连接信号槽
    connect(clientSocket, &QSslSocket::sslErrors, this, &YourClass::onSslErrors);
    connect(clientSocket, &QSslSocket::encrypted, this, &YourClass::onSslEncrypted);
}

void onSslErrors(const QList<QSslError> &errors) {
    QSslSocket *clientSocket = qobject_cast<QSslSocket *>(sender());

    // 处理SSL错误
    for (const QSslError &error : errors) {
        qDebug() << "SSL error:" << error.errorString();
    }

    // 如果不接受错误,断开连接
    clientSocket->abort();
}

void onSslEncrypted() {
    QSslSocket *clientSocket = qobject_cast<QSslSocket *>(sender());

    // 获取客户端证书
    QSslCertificate clientCert = clientSocket->peerCertificate();

    if (!clientCert.isNull()) {
        // 获取证书的 Common Name
        QString commonName = clientCert.subjectInfo(QSslCertificate::CommonName);

        // 根据 Common Name 标记客户端
        clientSocket->setProperty("clientTag", commonName);
        qDebug() << "Client connected. CN:" << commonName;
    } else {
        qDebug() << "Client certificate is null.";
    }

    // 处理客户端连接
    connect(clientSocket, &QSslSocket::readyRead, this, &YourClass::onReadyRead);
    connect(clientSocket, &QSslSocket::disconnected, clientSocket, &QSslSocket::deleteLater);
}

void onReadyRead() {
    QSslSocket *clientSocket = qobject_cast<QSslSocket *>(sender());

    if (clientSocket) {
        // 获取客户端标记
        QString clientTag = clientSocket->property("clientTag").toString();

        qDebug() << "Data received from" << clientTag << ":" << clientSocket->readAll();
    }
}

总结

  1. 创建自定义CA:生成CA的私钥和自签名证书,并配置CA的配置文件。
  2. 生成客户端证书:为每个客户端生成私钥和证书请求,并使用CA签署这些证书。
  3. 在服务器端加载CA证书:服务器只需加载CA的证书,并信任所有由该CA签发的客户端证书。
  4. 验证客户端证书并标记客户端:在客户端连接时,验证其证书,并根据 Common Name 进行标记。

 


http://www.kler.cn/a/441955.html

相关文章:

  • 【服务器】Ubuntu22.04配置静态ip
  • 第2章:Python TDD构建Dollar类基础
  • 深度学习中的张量 - 使用PyTorch进行广播和元素级操作
  • 算法(蓝桥杯)贪心算法5——删数问题的解题思路
  • 使用 Blazor 和 Elsa Workflows 作为引擎的工作流系统开发
  • js: 区分后端返回数字是否为null、‘-’ 或正常number类型数字。
  • 在 Linux 系统中,让 apt 使用 HTTP 代理
  • 文件上传之文件内容检测
  • 项目23:简易网络爬虫 --- 《跟着小王学Python·新手》
  • 突破时间与空间限制的富媒体百宝箱——智能工具箱:让云上内容生产更easy
  • 如何评估并持续优化AI呼入机器人的使用效果
  • ae学习笔记
  • Spring基础分析07-Spring JdbcTemplate
  • 【软件工程复习】
  • Android 解决“Could not resolve all artifacts for configuration ‘:classpath‘方法
  • 白话java设计模式
  • 单片机:实现pwm调光(附带源码)
  • 【人工智能数学基础篇】——深入详解基本概率论之概率分布(正态分布、伯努利分布等)、期望、方差等概念
  • 少样本学习之CAML算法
  • 【DevOps工具篇】SCM之Gitlab
  • 【BUG记录】Apifox 参数传入 + 号变成空格的 BUG
  • Cherno C++学习笔记 P41 运算符与重载
  • Elasticsearch:使用 Open Crawler 和 semantic text 进行语义搜索
  • 华为HarmonyOS帮助应用实现在线认证服务 -- 2 FIDO免密身份认证
  • [Unity]在unity 中输出调试安卓真机日志
  • react Ant Design