Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
SignedData.cs
1using System;
8
10{
14 public class SignedData() : SecurityObject()
15 {
19 public override string Oid => "1.2.840.113549.1.7.2";
20
24 public Vector? Asn1Vector { get; private set; }
25
29 public System.Numerics.BigInteger Version { get; private set; }
30
34 public HashFunction[] DigestAlgorithms { get; private set; } = [];
35
39 public string EncapsulatedContentOid { get; private set; } = string.Empty;
40
44 public byte[] EncapsulatedContent { get; private set; } = [];
45
49 public SignerInfo[] SignerInfos { get; private set; } = [];
50
54 public Certificate[] Certificates { get; private set; } = [];
55
59 public ContextSpecific? RevocationInfoChoices { get; private set; }
60
64 public override bool IsConfigured => this.Asn1Vector is not null;
65
71 public override bool Configure(Vector SecurityInfo)
72 {
73 if (SecurityInfo.Length != 2 ||
74 SecurityInfo.LastElement is not Vector SignedDataVector)
75 {
76 return false;
77 }
78
79 if (SignedDataVector.Length == 1 &&
80 SignedDataVector.FirstElement is Vector SignedDataVector2)
81 {
82 SignedDataVector = SignedDataVector2;
83 }
84
85 if (SignedDataVector.Length < 4)
86 return false;
87
88 if (SignedDataVector.FirstElement is not System.Numerics.BigInteger Version)
89 return false;
90
91 if (SignedDataVector[1] is not Vector DigestAlgorithms)
92 return false;
93
94 if (SignedDataVector[2] is not Vector EncapsulatedContent ||
95 EncapsulatedContent.Length < 2)
96 {
97 return false;
98 }
99
100 byte[] BinaryContent;
101 string ContentOid;
102
103 if (EncapsulatedContent.FirstElement is ISecurityObject SecurityObject)
104 ContentOid = SecurityObject.Oid;
105 else if (EncapsulatedContent.FirstElement is string s)
106 ContentOid = s;
107 else if (EncapsulatedContent.FirstElement is Vector v &&
108 v.FirstElement is string s2)
109 {
110 ContentOid = s2;
111 }
112 else
113 return false;
114
115 if (EncapsulatedContent[1] is byte[] Bin)
116 BinaryContent = Bin;
117 else if (EncapsulatedContent[1] is Vector ContentVector)
118 {
119 if (ContentVector.Length == 1)
120 {
121 if (ContentVector.FirstElement is byte[] EmbeddedContent)
122 BinaryContent = EmbeddedContent;
123 else if (ContentVector.FirstElement is Vector EmbeddedContent2)
124 BinaryContent = EmbeddedContent2.SubSection;
125 else
126 BinaryContent = ContentVector.SubSection;
127 }
128 else
129 BinaryContent = ContentVector.SubSection;
130 }
131 else
132 return false;
133
134 ContextSpecific? CertificateSet = null;
135 ContextSpecific? RevocationInfoChoices = null;
136
137 for (int i = 3; i < SignedDataVector.Length - 1; i++)
138 {
139 if (SignedDataVector[i] is ContextSpecific v)
140 {
141 switch (v.Tag)
142 {
143 case 0:
144 CertificateSet = v;
145 break;
146
147 case 1:
148 RevocationInfoChoices = v;
149 break;
150 }
151 break;
152 }
153 }
154
155 if (SignedDataVector.LastElement is not Vector SignerInfos)
156 return false;
157
158 ChunkedList<SignerInfo> SignerInfoList = [];
159
160 foreach (object Item in SignerInfos.Elements)
161 {
162 if (Item is not Vector SignerInfoVector ||
163 !SignerInfo.TryParse(SignerInfoVector, out SignerInfo? Parsed))
164 {
165 return false;
166 }
167
168 SignerInfoList.Add(Parsed);
169 }
170
171 ChunkedList<HashFunction> HashAlgorithms = [];
172
173 while (DigestAlgorithms.Length == 1 &&
174 DigestAlgorithms.FirstElement is Vector v)
175 {
176 DigestAlgorithms = v;
177 }
178
179 foreach (object Algorithm in DigestAlgorithms.Elements)
180 {
181 if (Algorithm is HashFunction HashFunction)
182 HashAlgorithms.Add(HashFunction);
183 }
184
185 ChunkedList<Certificate> Certificates = [];
186
187 if (CertificateSet is not null)
188 {
189 foreach (object Item in CertificateSet.Elements)
190 {
191 if (Item is Vector CertificateVector &&
192 Certificate.TryParse(CertificateVector, out Certificate? Parsed))
193 {
194 Certificates.Add(Parsed);
195 }
196 else
197 return false;
198 }
199 }
200
201 this.Asn1Vector = SecurityInfo;
202 this.Version = Version;
203 this.DigestAlgorithms = [.. HashAlgorithms];
204 this.EncapsulatedContentOid = ContentOid;
205 this.EncapsulatedContent = BinaryContent;
206 this.Certificates = [.. Certificates];
207 this.RevocationInfoChoices = RevocationInfoChoices;
208 this.SignerInfos = [.. SignerInfoList];
209
210 return true;
211 }
212
218 public bool CheckSignature(bool VerifyCertificates)
219 {
220 return this.CheckSignature(VerifyCertificates, null);
221 }
222
229 public bool CheckSignature(bool VerifyCertificates, ICommunicationLayer? Client)
230 {
231 if (!this.IsConfigured ||
232 this.SignerInfos is null ||
233 this.EncapsulatedContent is null)
234 {
235 return false;
236 }
237
238 bool SignatureValidated = false;
239
240 foreach (SignerInfo Info in this.SignerInfos)
241 {
242 if (Info.DigestAlgorithm is null ||
243 Info.MessageDigest is null ||
244 Info.SignatureAlgorithm is null)
245 {
246 continue;
247 }
248
249 if (!string.IsNullOrEmpty(Info.ContentType) &&
250 Info.ContentType != this.EncapsulatedContentOid)
251 {
252 continue;
253 }
254
255 byte[] Digest = Info.DigestAlgorithm.ComputeHash(this.EncapsulatedContent);
256
257 if (Convert.ToBase64String(Digest) != Convert.ToBase64String(Info.MessageDigest))
258 {
259 Client?.Error("Computed digest does not match message digest in signer info.");
260 return false;
261 }
262
263 Client?.Information("Computed digest matches message digest in signer info.");
264
265 Certificate? SelectedCertificate = null;
266
267 foreach (Certificate Certificate in this.Certificates)
268 {
269 if (Info.SerialNumber.HasValue && Certificate.SerialNumber == Info.SerialNumber)
270 {
271 SelectedCertificate = Certificate;
272 break;
273 }
274 else if (Info.SubjectKeyIdentifier is not null)
275 {
276 KeyValuePair<string?, byte[]?> P = TravelDocumentsClient.GetSubjectKeyIdentifier(Certificate);
277
278 if (P.Value is not null &&
279 Convert.ToBase64String(Info.SubjectKeyIdentifier) ==
280 Convert.ToBase64String(P.Value))
281 {
282 SelectedCertificate = Certificate;
283 break;
284 }
285 }
286 }
287
288 if (SelectedCertificate is null)
289 {
290 Client?.Error("Certificate used to sign message not found among included certificates.");
291 continue;
292 }
293
294 if (Info.HasSignedAttributes)
295 Digest = Info.SignedAttributesData;
296
297 if (Info.SignatureAlgorithm.VerifySignature(Digest, Info.Signature,
298 SelectedCertificate.PublicKey, Client))
299 {
300 Client?.Information("Signature validated successfully.");
301 SignatureValidated = true;
302
303 if (VerifyCertificates)
304 {
305 // TODO: Validate
306 }
307 break;
308 }
309 else
310 {
311 Client?.Error("Signature validation failed.");
312 return false;
313 }
314 }
315
316 if (!SignatureValidated)
317 {
318 Client?.Error("No signature validated.");
319 return false;
320 }
321
322 return true;
323 }
324 }
325}
Certificate, as defined in RFC 5280, §4.1.
Definition: Certificate.cs:13
static bool TryParse(byte[] RawCertificate, [NotNullWhen(true)] out Certificate? Parsed)
Tries to parse an ASN.1-encoded Certificate, as defined in RFC 5280, §4.1.
Definition: Certificate.cs:36
System.Numerics.BigInteger SerialNumber
Serial Number
Definition: Certificate.cs:121
abstract byte[] ComputeHash(byte[] Data)
Computes a Hash Digest from binary data.
Abstract base class for security objects.
abstract string Oid
OID identifying the type of object.
Signer Information, as defined in RFC 5652, §5.3.
Definition: SignerInfo.cs:17
byte[] SignedAttributesData
Binart representation of the signed attributes, as they are used in signature validation.
Definition: SignerInfo.cs:59
static bool TryParse(Vector SignerInfoVector, [NotNullWhen(true)] out SignerInfo? Parsed)
Tries to parse an ASN.1-encoded Signer Information structure, as defined in RFC 5652,...
Definition: SignerInfo.cs:98
byte?[] SubjectKeyIdentifier
Signer Subject Key Identifier.
Definition: SignerInfo.cs:43
System.Numerics.? BigInteger SerialNumber
Signer serial number.
Definition: SignerInfo.cs:38
bool HasSignedAttributes
If there are signed attributes.
Definition: SignerInfo.cs:64
ISignatureAlgorithm? SignatureAlgorithm
Signature algorithm
Definition: SignerInfo.cs:79
A chunked list is a linked list of chunks of objects of type T .
Definition: ChunkedList.cs:54
void Add(T Item)
Adds an item to the collection.
Definition: ChunkedList.cs:272
void Information(string Comment)
Called to inform the viewer of something.
void Error(string Error)
Called to inform the viewer of an error state.
Interface for observable classes implementing communication protocols.
class ContextSpecific(int Tag, Array Elements, byte[] SubSection)
A context-specific object (or set of objects).
class SignedData()
Signed Data, as defined in RFC 5652, §5.1.
Definition: SignedData.cs:14