Skip to content

Commit

Permalink
ca
Browse files Browse the repository at this point in the history
  • Loading branch information
dayu521 committed Feb 8, 2024
1 parent 8b13a54 commit fc51f51
Show file tree
Hide file tree
Showing 13 changed files with 550 additions and 66 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ linux下使用clang>16,在debug下编译

windows使用最新编译器

打开终端或`wt`
打开终端或`windows terminal`

```shell
xmake g --proxy_pac=github_mirror.lua
Expand Down
327 changes: 327 additions & 0 deletions src/certificate/cert.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,327 @@
#include "cert.h"

#include <cstring>

// X509_new
namespace hcpp
{

// 创建pkey
EVP_PKEY *generate_pkey()
{
// 创建key
EVP_PKEY_CTX *ctx;
EVP_PKEY *pkey = NULL;

ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if (!ctx)
/* Error occurred */
return nullptr;
if (EVP_PKEY_keygen_init(ctx) <= 0)
/* Error */
return nullptr;
if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048) <= 0)
/* Error */
return nullptr;
/* Generate key */
if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
/* Error */
return nullptr;

return pkey;
}

X509 *make_x509()
{
return X509_new();
}

EVP_PKEY *make_pkey()
{
return generate_pkey();
}

// Version
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.1
void set_version(X509 *cert)
{
// X509_set_version
X509_set_version(cert, X509_VERSION_3);
}

// Serial Number
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.2
void set_serialNumber(X509 *cert)
{
unsigned char buff[20];
if (RAND_bytes(buff, sizeof(buff)) != 1)
{
// 随机数生成失败,处理错误
}
buff[0] &= 0x7f; /* Ensure positive serial! */

BIGNUM *serial_bn = BN_bin2bn(buff, sizeof(buff), NULL);
if (serial_bn == NULL)
{
// 转换失败,处理错误
}
auto *serial = ASN1_INTEGER_new();
BN_to_ASN1_INTEGER(serial_bn, serial);

// X509_set_serialNumber >=3.2.0
X509_set_serialNumber(cert, serial);

ASN1_INTEGER_free(serial);
BN_free(serial_bn);
}

// Issuer
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.4
void add_issuer(X509 *cert, std::string_view name2)
{
// auto issuer = X509_NAME_new();
// * country,
// * organization,
// * organizational unit,
// x distinguished name qualifier,
// * state or province name,
// * common name (e.g., "Susan Housley"), and
// x serial number.

// * locality
struct name_entry
{
int nid_;
const char *nid_val_;
int nid_val_len_;
};
name_entry issuer[] = {
{NID_countryName, "CN", sizeof("CN") - 1},
{NID_organizationName, "NoBody", sizeof("NoBody") - 1},
{NID_organizationalUnitName, "XX", sizeof("XX") - 1},
{NID_stateOrProvinceName, "JS", sizeof("JS") - 1},
{NID_commonName, "SelfCA", sizeof("SelfCA") - 1},
{NID_localityName, "SQ", sizeof("SQ") - 1},
};

auto name = X509_NAME_new();

for (auto &&i : issuer)
{
X509_NAME_add_entry_by_NID(name, i.nid_, MBSTRING_ASC, (const unsigned char *)i.nid_val_, i.nid_val_len_, -1, 0);
}
// X509_set_issuer_name
X509_set_issuer_name(cert, name);
X509_NAME_free(name);
}

// Validity
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5
void set_validity(X509 *cert, std::size_t days)
{
// 这两个时间点都是包含的
auto begin_time = ASN1_TIME_new();
auto end_time = ASN1_TIME_new();
// now
X509_time_adj_ex(begin_time, 0, 0, nullptr);
X509_time_adj_ex(end_time, days, 0, nullptr);

X509_set1_notBefore(cert, begin_time);
X509_set1_notAfter(cert, end_time);
}

// Subject
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.6
void set_subject(X509 *cert)
{
// X509_set_subject_name get X509_NAME hashes or get and set issuer or subject names
X509_set_subject_name(cert, X509_get_issuer_name(cert));
}

// Subject Public Key Info
// https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.7
void set_pubkey(X509 *cert, EVP_PKEY *pkey)
{
X509_set_pubkey(cert, pkey);
}

/*********扩展**********/
// key usage
// https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.3
void add_ca_key_usage(X509 *cert)
{
auto bb = ASN1_BIT_STRING_new();
// ASN1_BIT_STRING_set_bit(bb, 6, 1);
// ASN1_BIT_STRING_set_bit(bb, 5, 1);
char8_t bv = KU_KEY_CERT_SIGN | KU_CRL_SIGN;
ASN1_BIT_STRING_set(bb, (unsigned char *)&bv, sizeof(bv));
X509_add1_ext_i2d(cert, NID_key_usage, bb, 1, X509_ADD_FLAG_DEFAULT);
ASN1_BIT_STRING_free(bb);
}

void generate_key_id(X509 *cert, unsigned char *md, std::size_t *md_len)
{
// 不要释放
// auto pubkey2 = X509_get0_pubkey(pkey);
// EVP_sha
// https://www.openssl.org/docs/manmaster/man3/X509_pubkey_digest.html
X509_pubkey_digest(cert, EVP_sha1(), md, (unsigned int *)md_len);

// EVP_PKEY_get_raw_public_key(pkey)
// EVP_PKEY
// or be replaced by (EVP_Q_digest(d, n, md, NULL, NULL, "SHA1", NULL) ? md : NULL)
// SHA1();
}
// Subject Key Identifier
// https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.2
void add_SKI(X509 *cert)
{
unsigned char md[EVP_MAX_MD_SIZE];
std::size_t md_len = 0;
generate_key_id(cert, md, &md_len);

auto oct = ASN1_OCTET_STRING_new();
ASN1_OCTET_STRING_set(oct, md, md_len);
X509_add1_ext_i2d(cert, NID_subject_key_identifier, oct, 0, X509V3_ADD_DEFAULT);
ASN1_OCTET_STRING_free(oct);
}

// Authority Key Identifier
// https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.1
void add_AKI(X509 *cert)
{
unsigned char md[EVP_MAX_MD_SIZE];
std::size_t md_len = 0;
generate_key_id(cert, md, &md_len);

auto oct = ASN1_OCTET_STRING_new();
ASN1_OCTET_STRING_set(oct, md, md_len);

auto akid = AUTHORITY_KEYID_new();
akid->keyid = oct;
akid->issuer = nullptr;
akid->serial = nullptr;
X509_add1_ext_i2d(cert, NID_authority_key_identifier, akid, 0, X509V3_ADD_DEFAULT);
ASN1_OCTET_STRING_free(oct);
}

// Subject Alternative Name
// https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.6
void add_DNS_SAN(X509 *caCert, std::string_view dns_name)
{
GENERAL_NAMES *gens = sk_GENERAL_NAME_new_null();

GENERAL_NAME *gen_dns = GENERAL_NAME_new();
ASN1_IA5STRING *ia5 = ASN1_IA5STRING_new();
ASN1_STRING_set(ia5, dns_name.data(), dns_name.length());
GENERAL_NAME_set0_value(gen_dns, GEN_DNS, ia5);
sk_GENERAL_NAME_push(gens, gen_dns);

// in_addr_t ipv4 = inet_addr("10.0.0.1");
// GENERAL_NAME *gen_ip = GENERAL_NAME_new();
// ASN1_OCTET_STRING *octet = ASN1_OCTET_STRING_new();
// ASN1_STRING_set(octet, &ipv4, sizeof(ipv4));
// GENERAL_NAME_set0_value(gen_ip, GEN_IPADD, octet);
// sk_GENERAL_NAME_push(gens, gen_ip);

X509_add1_ext_i2d(caCert, NID_subject_alt_name, gens, 0, X509V3_ADD_DEFAULT);

sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
}

// Basic Constraints
// https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.9
void add_ca_BS(X509 *cert)
{
auto e1 = X509V3_EXT_conf_nid(nullptr, nullptr, NID_basic_constraints, "CA:true");
X509_EXTENSION_set_critical(e1, 1);
X509_add_ext(cert, e1, -1);
// XXX为啥不正确
// auto bs = BASIC_CONSTRAINTS_new();
// bs->ca = 1;
// bs->pathlen = nullptr;
// X509_add1_ext_i2d(cert, NID_basic_constraints, bs, 1, X509V3_ADD_DEFAULT);
}

// 签名
void sign(X509 *cert, EVP_PKEY *pkey)
{
X509_sign(cert, pkey, EVP_sha256());
}

std::string make_pem_str(X509 *cert)
{
BIO *bio = BIO_new(BIO_s_mem());
PEM_write_bio_X509(bio, cert);
auto cert_size = BIO_pending(bio);

auto cert_array = new char[cert_size + 1];
BIO_read(bio, cert_array, cert_size);
BIO_free_all(bio);
return cert_array;
}

std::string make_pem_str(EVP_PKEY *pkey)
{
BIO *bio = BIO_new(BIO_s_mem());
PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL);
auto pkey_size = BIO_pending(bio);
auto pkey_array = new char[pkey_size + 1];
BIO_read(bio, pkey_array, pkey_size);
BIO_free_all(bio);
return pkey_array;
}

void test()
{

auto cert = X509_new();

auto pkey = generate_pkey();
// if (pkey == NULL)
// CHECK(false);
// print_key(pkey);

// set_version(cert);
// set_validity(cert);
// set_serialNumber(cert);
// add_issuer(cert);
// set_subject(cert);
// // add_SAN(cert);
// add_ca_BS(cert);
// add_AKI(cert);
// add_SKI(cert);
// add_ca_key_usage(cert);
// set_pubkey(cert, pkey);
// sign(cert, pkey);

// print_cert(cert);

// Save the private key to a file.
// FILE *privateKeyFile = fopen("hcpp.key.pem", "w");
// if (!privateKeyFile)
// {
// // CHECK(false);
// }
// if (!PEM_write_PrivateKey(privateKeyFile, pkey, nullptr, nullptr, 0, nullptr, nullptr))
// {
// fclose(privateKeyFile);
// // CHECK(false);
// }
// fclose(privateKeyFile);

// // Save the CA certificate to a file.
// // auto certfile="cert";

// FILE *caCertFile = fopen("hcpp.crt.pem", "wb");
// if (!caCertFile)
// {
// X509_free(cert);
// // CHECK(false);
// }
// PEM_write_X509(caCertFile, cert);

// fclose(caCertFile);
// X509_free(cert);
}
} // namespace hcpp
32 changes: 32 additions & 0 deletions src/certificate/cert.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef SRC_CERTIFICATE_CERT
#define SRC_CERTIFICATE_CERT

#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/pem.h>
#include <openssl/rand.h>

#include <string>

namespace hcpp
{
X509 * make_x509();
EVP_PKEY * make_pkey();
void set_version(X509 *cert);
void set_serialNumber(X509 *cert);
void add_issuer(X509 *cert,std::string_view name);
void set_validity(X509 *cert,std::size_t days=365*10);
void set_subject(X509 *cert);
void set_pubkey(X509 *cert, EVP_PKEY *pkey);
void add_ca_key_usage(X509 *cert);
void add_SKI(X509 *cert);
void add_AKI(X509 *cert);
void add_DNS_SAN(X509 *cert, std::string_view dns_name);
void add_ca_BS(X509 *cert);
void sign(X509 *cert, EVP_PKEY *pkey);

std::string make_pem_str(X509 *cert);
std::string make_pem_str(EVP_PKEY *pkey);
} // namespace hcpp

#endif /* SRC_CERTIFICATE_CERT */
4 changes: 2 additions & 2 deletions src/dns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ namespace hcpp
tcp_socket s(c);
co_await asio::async_connect(s, endpoints);

auto ssl_m = std::make_shared<ssl_sock_mem>(asio::ssl::stream_base::client);
ssl_m->init(std::move(s));
auto ssl_m = std::make_shared<ssl_sock_mem>(provider.host_,"https");
ssl_m->init_client(std::move(s));
co_await ssl_m->async_handshake();
co_await ssl_m->wait();

Expand Down
11 changes: 11 additions & 0 deletions src/hcpp-cfg.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,16 @@
"sni_host_":"", //假的主机名
"close_sni_":false //默认就是false.优先级高于sni_host_
}
,
{

"host_":"www.baidu.com",
"svc_":"443", //端口或服务名.例如 http https
"url_":"", //暂未使用
"mitm_":true,
"doh_":false,
"sni_host_":"", //假的主机名
"close_sni_":false //默认就是false.优先级高于sni_host_
}
]
}
Loading

0 comments on commit fc51f51

Please sign in to comment.