首先,您尝试做的事情是行不通的。PGP 和 S/MIME 从根本上是不兼容的。将您朋友的 PGP 公钥放入 x.509 证书将不允许您使用 S/MIME 工具与他通信。要么您都需要使用 S/MIME,要么都需要使用 PGP。你不能混合。
至于这是否可以做到:证书必须由某人签名。因此,如果您有公钥,则可以将其嵌入到由其他人签名的证书中,但如果没有私钥,您将无法创建自签名证书。
但这里有一个问题:面向用户的工具(例如 openssl 命令行)只会创建证书(a)使用私钥自签名,或(b)通过签署请求。
并且签名请求本身使用它们嵌入的密钥进行签名。这个想法是,如果你要为某人创建一个证书,你想验证他们是否真的拥有你正在认证的密钥。
但是...当您深入了解内部结构时,例如使用 openSSL API 函数,您几乎可以做任何您想做的事情。您可以创建未签名的请求和证书[1](可能不会在任何地方得到认可),并且您可以仅使用公钥和一些属性来创建证书。
您可能想直接查看使用 openssl C api,或者可能是为其他语言构建的优秀库之一。
这是 Ruby 中的一个示例:此示例由grawity提供作为编辑。我没有测试过这段代码。
#!/usr/bin/env ruby
require 'openssl'
pkey_data = File.read("id_rsa")
pkey_password = ""
subject = "/O=Honest Achmed's Used Cars and Certificates/OU=Self-made/CN=Geremia's cert"
expiry_years = 1
# Fill basic v1 fields
cert = OpenSSL::X509::Certificate.new
cert.version = 2 # for X.509 v3
cert.serial = 1
cert.subject = OpenSSL::X509::Name.parse(subject)
cert.issuer = cert.subject
cert.not_before = Time.now
cert.not_after = Time.now + (expiry_years * 365 * 86400)
# Add v3 extensions
extf = OpenSSL::X509::ExtensionFactory.new
extf.subject_certificate = cert
extf.issuer_certificate = cert
cert.extensions = [
# basicConstraints is marked as 'critical' here
extf.create_extension("basicConstraints", "CA:FALSE", true),
extf.create_extension("subjectKeyIdentifier", "hash"),
# 'copy' means needed information will be taken from subjectKeyIdentifier
extf.create_extension("authorityKeyIdentifier",
"keyid:copy, issuer:copy"),
extf.create_extension("keyUsage",
"digitalSignature, keyEncipherment, nonRepudiation"),
extf.create_extension("extendedKeyUsage",
"clientAuth, serverAuth, emailProtection"),
]
# Add public key and self-sign – if you omit the cert.sign()
# call, you WILL have an unsigned certificate made just with the public key.
pkey = OpenSSL::PKey::RSA.new(pkey_data, pkey_password)
cert.public_key = pkey
cert.sign(pkey, OpenSSL::Digest::SHA1.new)
# Output in PEM format (aka base64-encoded DER)
puts cert.to_pem
- [1]大约十年前,我为 .NET 创建了一个 OpenSSL 互操作库,它偶然做了这些事情。幸运的是,除了我,没有人见过这个项目。