计算公钥Pin (. net)
本文关键字:net Pin 公钥 计算 | 更新日期: 2023-09-27 18:06:31
我想知道如何计算X509证书的公钥引脚?
例如。我已经通过web请求获得了证书
var cert = (httpRequest as HttpWebRequest).ServicePoint.Certificate;
X509Certificate2 cert2 = new X509Certificate2(cert);
我不知道在此之后该怎么做,因为我需要主题公钥信息(散列它),但我找不到它在X509Certificate2类或确定如何构建它。我可以通过GetKeyInfo()方法获得指数和模数,这似乎是SPKI的核心。
我相信有一个简单的方法来做到这一点,但任何帮助将是伟大的!谢谢
短版
辅助方法:
String publicKeyPinningHash = certificate.GetPublicKeyPinningHash();
String s = String.Format("Public-Key-Pins: pin-sha256='"{0}'";
max-age=31536000", publicKeyHash);
为Facebook.com吐出:
Public-Key-Pins: pin-sha256 = " hUIG87ch71EZQYhZBEkq2VKBLjhussUw7nR8wyuY7rY = ";信息= 31536000
功能。net Fiddle
https://dotnetfiddle.net/F9t6IQ 的背景正如您所发现的,. net框架没有能力操作X509Certificate。X。509证书使用ASN.1的DER风格进行编码。. net框架没有能力操作AsnEcodedData。
这意味着我们需要自己编写代码来计算X.509证书的PublicKeyPinning散列:
static String GetPublicKeyPinningHash(X509Certificate2 x509Cert)
{
//Public Domain: No attribution required
//Get the SubjectPublicKeyInfo member of the certificate
Byte[] subjectPublicKeyInfo = GetSubjectPublicKeyInfoRaw(x509Cert);
//Take the SHA2-256 hash of the DER ASN.1 encoded value
Byte[] digest;
using (var sha2 = new SHA256Managed())
{
digest = sha2.ComputeHash(subjectPublicKeyInfo);
}
//Convert hash to base64
String hash = Convert.ToBase64String(digest);
return hash;
}
这段代码是建立在较低的函数,也没有提供,以获得原始的SubjectPublickeyInfo字节:
static Byte[] GetSubjectPublicKeyInfoRaw(X509Certificate2 x509Cert)
{
//Public Domain: No attribution required
Byte[] rawCert = x509Cert.GetRawCertData();
/*
Certificate is, by definition:
Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING
}
TBSCertificate ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,
validity Validity,
subject Name,
subjectPublicKeyInfo SubjectPublicKeyInfo,
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, -- If present, version MUST be v2 or v3
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, -- If present, version MUST be v2 or v3
extensions [3] EXPLICIT Extensions OPTIONAL -- If present, version MUST be v3
}
So we walk to ASN.1 DER tree in order to drill down to the SubjectPublicKeyInfo item
*/
Byte[] list = AsnNext(ref rawCert, true); //unwrap certificate sequence
Byte[] tbsCertificate = AsnNext(ref list, false); //get next item; which is tbsCertificate
list = AsnNext(ref tbsCertificate, true); //unwap tbsCertificate sequence
Byte[] version = AsnNext(ref list, false); //tbsCertificate.Version
Byte[] serialNumber = AsnNext(ref list, false); //tbsCertificate.SerialNumber
Byte[] signature = AsnNext(ref list, false); //tbsCertificate.Signature
Byte[] issuer = AsnNext(ref list, false); //tbsCertificate.Issuer
Byte[] validity = AsnNext(ref list, false); //tbsCertificate.Validity
Byte[] subject = AsnNext(ref list, false); //tbsCertificate.Subject
Byte[] subjectPublicKeyInfo = AsnNext(ref list, false); //tbsCertificate.SubjectPublicKeyInfo
return subjectPublicKeyInfo;
}
构建在较低层函数上,用于解析ASN.1编码的数据,这些数据使用ASN.1的DER风格进行编码:
static Byte[] AsnNext(ref Byte[] buffer, Boolean unwrap)
{
//Public Domain: No attribution required
Byte[] result;
if (buffer.Length < 2)
{
result = buffer;
buffer = new Byte[0];
return result;
}
int index = 0;
Byte entityType = buffer[index];
index += 1;
int length = buffer[index];
index += 1;
int lengthBytes = 1;
if (length >= 0x80)
{
lengthBytes = length & 0x0F; //low nibble is number of length bytes to follow
length = 0;
for (int i = 0; i < lengthBytes; i++)
{
length = (length << 8) + (int)buffer[2 + i];
index += 1;
}
lengthBytes++;
}
int copyStart;
int copyLength;
if (unwrap)
{
copyStart = 1 + lengthBytes;
copyLength = length;
}
else
{
copyStart = 0;
copyLength = 1 + lengthBytes + length;
}
result = new Byte[copyLength];
Array.Copy(buffer, copyStart, result, 0, copyLength);
Byte[] remaining = new Byte[buffer.Length - (copyStart+copyLength)];
if (remaining.Length > 0)
Array.Copy(buffer, copyStart + copyLength, remaining, 0, remaining.Length);
buffer = remaining;
return result;
}
公钥绑定是指验证证书的公钥是否正确。公钥不需要计算,它以明文形式包含在证书中。我认为您的意思是,您想要计算公钥的散列(固定不意味着散列,它意味着与已知值进行比较)。如果您知道后端URL或IP,则可以轻松地提取公钥。
chrome页面示例(需要OpenSSL工具):
- 点击URL左侧的绿色锁
- 点击详情
- 点击安全 中的"查看证书"
- 转到"详细信息"选项卡并"复制到文件"并保存在某处
使用
openssl x509 -inform der -in yourcertificate.cer-pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary
它将返回公钥的sha256哈希值