openssl 数字证书_使用OpenSSL库签署数字证书

openssl 数字证书

在使用pgopenssltypes扩展时,我意识到我还没有讨论如何使用OpenSSL库对数字证书进行签名。 (至少我不记得这样做了–我可能在博客的早期就对此进行了讨论。我敢肯定,我已经讨论过使用BouncyCastle(java)库对数字证书进行签名。)

我的pgopenssltypes扩展将具有签名数字证书以进行测试的能力,但实际工作将在可能的pgca扩展中完成。 成为CA不仅需要签署简单证书的能力。

签署证书的基本代码很简单。

BIGNUM *serialNumber;
X509_NAME *issuerName;
X509_NAME *subjectName;
time_t notBefore;
time_t notAfter;
EVP_PKEY *issuerKey; // private key
EVP_PKEY *subjectKey; // public key

// allocate memory for a cert.
X509 cert = X509_new();

// this is standard
X509_set_version(cert, 3);

// set the the mandatory fields.
X509_set_serialNumber(cert, BN_to_ASN1_INTEGER(serialNumber, NULL));
X509_set_issuer_name(cert, issuerName);
X509_set_subject_name(cert, subjectName);
X509_set_notBefore(cert, ASN1_TIME_set(NULL, notBefore));
X509_set_notAfter(cert, ASN1_TIME_set(NULL, notAfter));
X509_set_pubkey(cert, subjectKey);

// sign the certificate. In this case I'm using SHA256 for the hash.
if ((r = X509_sign(cert, issuerKey, EVP_sha256())) <= 0) {
    fprintf(STDERR, "%s", ERR_reason_error_string(ERR_get_error());
    X509_free(cert);
    return NULL;
}

// release the memory
PKCS8_PRIV_KEY_INFO_free(p8);
EVP_PKEY_free(pkey);

// write certificate to file
// FILE *fp = fopen(...)
// PEM_write_X509(fp, cert);

return cert;

有一个使用X509_REQ而不是X509对象的变体,但这是不重要的更改。 (我记得X509_REQ是特殊的自签名X509证书,主要由完整的证书颁发机构(CA)使用。)

发行方通常与自己的数字证书无限制关联。 这形成了“证书链”,其中每个证书的颁发者是下一个证书的主题。 链以“受信任”证书(由用户决定什么是“受信任”)或自签名证书(由用户决定哪个主题/发布者是多少)结束“受信任”)。

证书本身不是跟踪公钥的便捷方法,没有任何价值。 证书链只能用于可信任每个中间签名者的身份验证。

最后,上面的代码将很乐意允许使用任何密钥来签署证书。 在行为良好的应用程序中,将检查颁发者证书中的“基本约束” –该数字指定可以签名多少个附加级别,并且每一代应至少丢弃一个附加级别。

资料类型

该代码包含几种不熟悉的数据类型。

BIGNUM是任意长度整数的OpenSSL实现。 某些CA使用128或160位序列号,而不是同时使用MD5或SHA1哈希值的长度。 但是,这只是一个惯例,没有理由为什么攻击者无法使用10k字节的序列号来尝试在编写不良的代码尝试读取缓冲区时导致缓冲区溢出。

有一个宽松的约定,即序列号较高的证书比序列号较低的证书发行晚。 许多CA不遵循此约定。

一些CA担心简单的序列会泄漏敏感信息,即已颁发了多少证书。 常见的对策是使用基于日期的序列号,例如,十六进制值可以是0x20141230NNNNNN,其中NNNNNN是时间,伪随机数或某种组合。

最后,谨慎的CA可能会在序列号本身中编码信息。 例如,它可以悄悄地确保序列号始终为3 mod 17,或者类似的值反映证书中其他位置存在的信息。 有权访问CA私钥的攻击者可能没有意识到这些检查,而在野外发现错误的序列号可能是出现漏洞的第一个迹象。

EVP_PKEY是通用私钥或公钥。 它可以包含RSA,ECC,DSA或DH密钥。 我认为在创建数字证书(可能是带有低功耗设备的ECC)时,我们只关心RSA密钥。

我们可以使用以下方法将RSA密钥转换为EVP_PKEY:

RSA *rsa;
EVP_PKEY *pkey;

pkey = EVP_PKEY_new();
if (EVP_PKEY_set1_RSA(pkey, rsa) <= 0) {
    fprintf(STDERR, "%s", ERR_reason_error_string(ERR_get_error());
    EVP_PKEY_free(pkey);
    return NULL;
}

return pkey;

将.p8(PKCS8)密钥转换为EVP_PKEY也很容易:

PKCS8_PRIV_KEY_INFO *p8;
EVP_PKEY *pkey;

pkey = EVP_PKCS82PKEY(p8);
if (pkey == null) {
    fprintf(STDERR, "%s", ERR_reason_error_string(ERR_get_error());
    return NULL;
}

return pkey;

X509_NAME与LDAP专有名称相同。 从字面上看-它们来自相同的X.500标准。 (因此X509。)许多体系结构都利用了这一点–这是将用户的数字证书与企业目录服务绑定的好方法。

X509_NAME是X509_NAME_ENTRY值的堆栈。 每个条目都是一个键值对。 例如,“ CN = Bear Giles,C = US,ST = Colorado”将具有三个X509_NAME_ENTRY值–(“ CN”,“ Bear Giles”),(“ C”,“ US”),(“ ST”,“科罗拉多”。 有几十个标准键,其中一些可以重复。 (例如,域组件的“ DC”。invariantproperties.com上的服务器将为“ DC = invariantproperties,DC = com”。)有关更多详细信息,请参见RFC 4519属性类型。

(旁注:LDAP通常具有上面显示的格式。OpenSSL倾向于用斜杠代替逗号,例如“ CN = Bear Giles / C = US / ST = Colorado”。)

您可以使用以下命令打印X509_NAME:

X509_NAME *name;
char buf[BUF_LEN];

X509_NAME_oneline(name, buf, BUF_LEN);

要么:

BIO *bio;  // can point to memory buffer, file, etc.
X509_NAME *name;
int obase; // indentation on multi-line output.

X509_NAME_print(bio, name, obase);

创建X509_NAME对象要复杂一些。

char *name;              // e.g., "C" for Country
unsigned char *value;    // e.g., "US"
int type = MBSTRING_ASC; // or MBSTRING_UTF8
X509_NAME *name;

// value is null-terminated string.
int len = -1;

// these values add entry to end of X509_NAME.
int loc = -1;
int set = 0;

name = X509_NAME_new();
if (X509_NAME_add_entry_by_txt(name, key, type, value, len, loc, set) <= 0) {
    fprintf(STDERR, "%s", ERR_reason_error_string(ERR_get_error());
    return NULL;
}

扩展名

X509v3证书的真正功能是可以使用任意信息进行扩展。 有十几种广泛使用的扩展名,但是任何人都可以获取新的ASN1 OID并将自己的信息添加到数字证书中。 (必须明确地请求并注册一个新的OID,如果将相同的OID用于不同的用途,则会引起问题。)仅必须注册根OID,才能自由创建子OID。

有关标准扩展的详细讨论超出了本文的范围。 需要满足的条件是它们可以提供有关密钥用法的信息(例如,应该使用证书对电子邮件进行加密,但不能在服务器上使用),证书的其他别名,甚至是对此证书签名的证书的限制。 (例如,它必须用于“ example.com”域下的服务器)。

非标准扩展名可能包括内部用户ID,进一步验证用户身份的生物特征,照片等。

翻译自: https://www.javacodegeeks.com/2015/01/signing-digital-certificates-with-openssl-library.html

openssl 数字证书

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值