mirrored from https://www.bouncycastle.org/repositories/bc-csharp
-
Notifications
You must be signed in to change notification settings - Fork 602
Expand file tree
/
Copy pathDeltaCertificateTool.cs
More file actions
158 lines (129 loc) · 6.73 KB
/
Copy pathDeltaCertificateTool.cs
File metadata and controls
158 lines (129 loc) · 6.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
using System;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X509;
namespace Org.BouncyCastle.X509
{
/// <summary>
/// General tool for handling the extension described in:
/// https://datatracker.ietf.org/doc/draft-bonnell-lamps-chameleon-certs/
/// </summary>
public class DeltaCertificateTool
{
public static Asn1.X509.Extension CreateDeltaCertificateExtension(bool isCritical,
X509CertificateStructure deltaCert)
{
var descriptor = new DeltaCertificateDescriptor(
deltaCert.SerialNumber,
signature: deltaCert.SignatureAlgorithm,
deltaCert.Issuer,
deltaCert.Validity,
deltaCert.Subject,
deltaCert.SubjectPublicKeyInfo,
deltaCert.Extensions,
signatureValue: deltaCert.Signature);
var extnID = X509Extensions.DRAFT_DeltaCertificateDescriptor;
var critical = DerBoolean.GetInstance(isCritical);
var extnValue = DerOctetString.WithContents(descriptor.GetEncoded(Asn1Encodable.Der));
return new Asn1.X509.Extension(extnID, critical, extnValue);
}
public static Asn1.X509.Extension CreateDeltaCertificateExtension(bool isCritical, X509Certificate deltaCert) =>
CreateDeltaCertificateExtension(isCritical, deltaCert.CertificateStructure);
public static X509CertificateStructure ExtractDeltaCertificate(TbsCertificateStructure baseTbsCert)
{
var baseExtensions = baseTbsCert.Extensions;
var dcdExtension = baseExtensions.GetExtension(X509Extensions.DRAFT_DeltaCertificateDescriptor) ??
throw new InvalidOperationException("no deltaCertificateDescriptor present");
var descriptor = DeltaCertificateDescriptor.GetInstance(dcdExtension.GetParsedValue());
var version = baseTbsCert.VersionNumber;
var serialNumber = descriptor.SerialNumber;
var signature = descriptor.Signature ?? baseTbsCert.Signature;
var issuer = descriptor.Issuer ?? baseTbsCert.Issuer;
var validity = descriptor.Validity ?? baseTbsCert.Validity;
var subject = descriptor.Subject ?? baseTbsCert.Subject;
var subjectPublicKeyInfo = descriptor.SubjectPublicKeyInfo;
var extensions = ExtractDeltaExtensions(descriptor.Extensions, baseExtensions);
// TODO Copy over the issuerUniqueID and/or subjectUniqueID (if the issuer/subject resp. are unmodified)?
var tbsCertificate = new TbsCertificateStructure(version, serialNumber, signature, issuer, validity,
subject, subjectPublicKeyInfo, issuerUniqueID: null, subjectUniqueID: null, extensions);
return new X509CertificateStructure(tbsCertificate, signature, descriptor.SignatureValue);
}
public static X509Certificate ExtractDeltaCertificate(X509Certificate baseCert) =>
new X509Certificate(ExtractDeltaCertificate(baseCert.TbsCertificate));
public static DeltaCertificateDescriptor TrimDeltaCertificateDescriptor(DeltaCertificateDescriptor descriptor,
TbsCertificateStructure tbsCertificate, X509Extensions tbsExtensions)
{
DerInteger serialNumber = descriptor.SerialNumber;
AlgorithmIdentifier signature = descriptor.Signature;
if (signature != null && signature.Equals(tbsCertificate.Signature))
{
signature = null;
}
X509Name issuer = descriptor.Issuer;
if (issuer != null && issuer.Equals(tbsCertificate.Issuer))
{
issuer = null;
}
Validity validity = descriptor.Validity;
if (validity != null && validity.Equals(tbsCertificate.Validity))
{
validity = null;
}
X509Name subject = descriptor.Subject;
if (subject != null && subject.Equals(tbsCertificate.Subject))
{
subject = null;
}
SubjectPublicKeyInfo subjectPublicKeyInfo = descriptor.SubjectPublicKeyInfo;
X509Extensions extensions = descriptor.Extensions;
if (extensions != null)
{
/*
* draft-bonnell-lamps-chameleon-certs-05 4.1:
*
* [The extensions] field MUST NOT contain any extension:
* - which has the same criticality and DER-encoded value as encoded in the Base Certificate,
* - whose type does not appear in the Base Certificate, or
* - which is of the DCD extension type (recursive Delta Certificates are not permitted).
*
* [...] The ordering of extensions in [the extensions] field MUST be relative to the ordering of the
* extensions as they are encoded in the Delta [recte Base] Certificate.
*/
X509ExtensionsGenerator generator = new X509ExtensionsGenerator();
foreach (DerObjectIdentifier oid in tbsExtensions.ExtensionOids)
{
if (X509Extensions.DRAFT_DeltaCertificateDescriptor.Equals(oid))
continue;
X509Extension deltaExtension = extensions.GetExtension(oid);
if (deltaExtension != null && !deltaExtension.Equals(tbsExtensions.GetExtension(oid)))
{
generator.AddExtension(oid, deltaExtension);
}
}
extensions = generator.IsEmpty ? null : generator.Generate();
}
DerBitString signatureValue = descriptor.SignatureValue;
return new DeltaCertificateDescriptor(serialNumber, signature, issuer, validity, subject,
subjectPublicKeyInfo, extensions, signatureValue);
}
private static X509Extensions ExtractDeltaExtensions(X509Extensions descriptorExtensions,
X509Extensions baseExtensions)
{
X509ExtensionsGenerator extGen = new X509ExtensionsGenerator();
foreach (var oid in baseExtensions.ExtensionOids)
{
if (!X509Extensions.DRAFT_DeltaCertificateDescriptor.Equals(oid))
{
extGen.AddExtension(oid, baseExtensions.GetExtension(oid));
}
}
if (descriptorExtensions != null)
{
foreach (var oid in descriptorExtensions.ExtensionOids)
{
extGen.ReplaceExtension(oid, descriptorExtensions.GetExtension(oid));
}
}
return extGen.IsEmpty ? null : extGen.Generate();
}
}
}