Merge pull request #629 from pruiz/syswebrouting-fixes2
[mono.git] / mcs / class / Mono.Security / Mono.Security / PKCS7.cs
1 //
2 // PKCS7.cs: PKCS #7 - Cryptographic Message Syntax Standard 
3 //      http://www.rsasecurity.com/rsalabs/pkcs/pkcs-7/index.html
4 //
5 // Authors:
6 //      Sebastien Pouliot <sebastien@ximian.com>
7 //      Daniel Granath <dgranath#gmail.com>
8 //
9 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
10 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System;
33 using System.Collections;
34 using System.Security.Cryptography;
35
36 using Mono.Security.X509;
37
38 namespace Mono.Security {
39
40 #if INSIDE_CORLIB
41         internal
42 #else
43         public
44 #endif
45         sealed class PKCS7 {
46
47                 public class Oid {
48                         // pkcs 1
49                         public const string rsaEncryption = "1.2.840.113549.1.1.1";
50                         // pkcs 7
51                         public const string data = "1.2.840.113549.1.7.1";
52                         public const string signedData = "1.2.840.113549.1.7.2";
53                         public const string envelopedData = "1.2.840.113549.1.7.3";
54                         public const string signedAndEnvelopedData = "1.2.840.113549.1.7.4";
55                         public const string digestedData = "1.2.840.113549.1.7.5";
56                         public const string encryptedData = "1.2.840.113549.1.7.6";
57                         // pkcs 9
58                         public const string contentType = "1.2.840.113549.1.9.3";
59                         public const string messageDigest  = "1.2.840.113549.1.9.4";
60                         public const string signingTime = "1.2.840.113549.1.9.5";
61                         public const string countersignature = "1.2.840.113549.1.9.6";
62
63                         public Oid () 
64                         {
65                         }
66                 }
67
68                 private PKCS7 ()
69                 {
70                 }
71
72                 static public ASN1 Attribute (string oid, ASN1 value) 
73                 {
74                         ASN1 attr = new ASN1 (0x30);
75                         attr.Add (ASN1Convert.FromOid (oid));
76                         ASN1 aset = attr.Add (new ASN1 (0x31));
77                         aset.Add (value);
78                         return attr;
79                 }
80
81                 static public ASN1 AlgorithmIdentifier (string oid)
82                 {
83                         ASN1 ai = new ASN1 (0x30);
84                         ai.Add (ASN1Convert.FromOid (oid));
85                         ai.Add (new ASN1 (0x05));       // NULL
86                         return ai;
87                 }
88
89                 static public ASN1 AlgorithmIdentifier (string oid, ASN1 parameters) 
90                 {
91                         ASN1 ai = new ASN1 (0x30);
92                         ai.Add (ASN1Convert.FromOid (oid));
93                         ai.Add (parameters);
94                         return ai;
95                 }
96
97                 /*
98                  * IssuerAndSerialNumber ::= SEQUENCE {
99                  *      issuer Name,
100                  *      serialNumber CertificateSerialNumber 
101                  * }
102                  */
103                 static public ASN1 IssuerAndSerialNumber (X509Certificate x509) 
104                 {
105                         ASN1 issuer = null;
106                         ASN1 serial = null;
107                         ASN1 cert = new ASN1 (x509.RawData);
108                         int tbs = 0;
109                         bool flag = false;
110                         while (tbs < cert[0].Count) {
111                                 ASN1 e = cert[0][tbs++];
112                                 if (e.Tag == 0x02)
113                                         serial = e;
114                                 else if (e.Tag == 0x30) {
115                                         if (flag) {
116                                                 issuer = e;
117                                                 break;
118                                         }
119                                         flag = true;
120                                 }
121                         }
122                         ASN1 iasn = new ASN1 (0x30);
123                         iasn.Add (issuer);
124                         iasn.Add (serial);
125                         return iasn;
126                 }
127
128                 /*
129                  * ContentInfo ::= SEQUENCE {
130                  *      contentType ContentType,
131                  *      content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL 
132                  * }
133                  * ContentType ::= OBJECT IDENTIFIER
134                  */
135                 public class ContentInfo {
136
137                         private string contentType;
138                         private ASN1 content;
139
140                         public ContentInfo () 
141                         {
142                                 content = new ASN1 (0xA0);
143                         }
144
145                         public ContentInfo (string oid) : this ()
146                         {
147                                 contentType = oid;
148                         }
149
150                         public ContentInfo (byte[] data) 
151                                 : this (new ASN1 (data)) {}
152
153                         public ContentInfo (ASN1 asn1) 
154                         {
155                                 // SEQUENCE with 1 or 2 elements
156                                 if ((asn1.Tag != 0x30) || ((asn1.Count < 1) && (asn1.Count > 2)))
157                                         throw new ArgumentException ("Invalid ASN1");
158                                 if (asn1[0].Tag != 0x06)
159                                         throw new ArgumentException ("Invalid contentType");
160                                 contentType = ASN1Convert.ToOid (asn1[0]);
161                                 if (asn1.Count > 1) {
162                                         if (asn1[1].Tag != 0xA0)
163                                                 throw new ArgumentException ("Invalid content");
164                                         content = asn1[1];
165                                 }
166                         }
167
168                         public ASN1 ASN1 {
169                                 get { return GetASN1(); }
170                         }
171
172                         public ASN1 Content {
173                                 get { return content; }
174                                 set { content = value; }
175                         }
176
177                         public string ContentType {
178                                 get { return contentType; }
179                                 set { contentType = value; }
180                         }
181
182                         internal ASN1 GetASN1 () 
183                         {
184                                 // ContentInfo ::= SEQUENCE {
185                                 ASN1 contentInfo = new ASN1 (0x30);
186                                 // contentType ContentType, -> ContentType ::= OBJECT IDENTIFIER
187                                 contentInfo.Add (ASN1Convert.FromOid (contentType));
188                                 // content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL 
189                                 if ((content != null) && (content.Count > 0))
190                                         contentInfo.Add (content);
191                                 return contentInfo;
192                         }
193
194                         public byte[] GetBytes () 
195                         {
196                                 return GetASN1 ().GetBytes ();
197                         }
198                 }
199
200                 /*
201                  * EncryptedData ::= SEQUENCE {
202                  *      version         INTEGER {edVer0(0)} (edVer0),
203                  *       encryptedContentInfo  EncryptedContentInfo
204                  * }
205                  */
206                 public class EncryptedData {
207                         private byte _version;
208                         private ContentInfo _content;
209                         private ContentInfo _encryptionAlgorithm;
210                         private byte[] _encrypted;
211
212                         public EncryptedData () 
213                         {
214                                 _version = 0;
215                         }
216
217                         public EncryptedData (byte[] data) 
218                                 : this (new ASN1 (data))
219                         {
220                         }
221
222                         public EncryptedData (ASN1 asn1) : this () 
223                         {
224                                 if ((asn1.Tag != 0x30) || (asn1.Count < 2))
225                                         throw new ArgumentException ("Invalid EncryptedData");
226
227                                 if (asn1 [0].Tag != 0x02)
228                                         throw new ArgumentException ("Invalid version");
229                                 _version = asn1 [0].Value [0];
230
231                                 ASN1 encryptedContentInfo = asn1 [1];
232                                 if (encryptedContentInfo.Tag != 0x30)
233                                         throw new ArgumentException ("missing EncryptedContentInfo");
234
235                                 ASN1 contentType = encryptedContentInfo [0];
236                                 if (contentType.Tag != 0x06)
237                                         throw new ArgumentException ("missing EncryptedContentInfo.ContentType");
238                                 _content = new ContentInfo (ASN1Convert.ToOid (contentType));
239
240                                 ASN1 contentEncryptionAlgorithm = encryptedContentInfo [1];
241                                 if (contentEncryptionAlgorithm.Tag != 0x30)
242                                         throw new ArgumentException ("missing EncryptedContentInfo.ContentEncryptionAlgorithmIdentifier");
243                                 _encryptionAlgorithm = new ContentInfo (ASN1Convert.ToOid (contentEncryptionAlgorithm [0]));
244                                 _encryptionAlgorithm.Content = contentEncryptionAlgorithm [1];
245                                 
246                                 ASN1 encryptedContent = encryptedContentInfo [2];
247                                 if (encryptedContent.Tag != 0x80)
248                                         throw new ArgumentException ("missing EncryptedContentInfo.EncryptedContent");
249                                 _encrypted = encryptedContent.Value;
250                         }
251
252                         public ASN1 ASN1 {
253                                 get { return GetASN1(); }
254                         }
255
256                         public ContentInfo ContentInfo {
257                                 get { return _content; }
258                         }
259
260                         public ContentInfo EncryptionAlgorithm {
261                                 get { return _encryptionAlgorithm; }
262                         }
263
264                         public byte[] EncryptedContent {
265                                 get {
266                                         if (_encrypted == null)
267                                                 return null;
268                                         return (byte[]) _encrypted.Clone ();
269                                 }
270                         }
271
272                         public byte Version {
273                                 get { return _version; }
274                                 set { _version = value; }
275                         }
276
277                         // methods
278
279                         internal ASN1 GetASN1 () 
280                         {
281                                 return null;
282                         }
283
284                         public byte[] GetBytes () 
285                         {
286                                 return GetASN1 ().GetBytes ();
287                         }
288                 }
289
290                 /*
291                  * EnvelopedData ::= SEQUENCE {
292                  *      version Version,
293                  *      recipientInfos RecipientInfos,
294                  *      encryptedContentInfo EncryptedContentInfo 
295                  * }
296                  * 
297                  * RecipientInfos ::= SET OF RecipientInfo
298                  * 
299                  * EncryptedContentInfo ::= SEQUENCE {
300                  *      contentType ContentType,
301                  *      contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
302                  *      encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL 
303                  * }
304                  * 
305                  * EncryptedContent ::= OCTET STRING
306                  * 
307                  */
308                 public class EnvelopedData {
309                         private byte _version;
310                         private ContentInfo _content;
311                         private ContentInfo _encryptionAlgorithm;
312                         private ArrayList _recipientInfos;
313                         private byte[] _encrypted;
314
315                         public EnvelopedData () 
316                         {
317                                 _version = 0;
318                                 _content = new ContentInfo ();
319                                 _encryptionAlgorithm = new ContentInfo ();
320                                 _recipientInfos = new ArrayList ();
321                         }
322
323                         public EnvelopedData (byte[] data) 
324                                 : this (new ASN1 (data))
325                         {
326                         }
327
328                         public EnvelopedData (ASN1 asn1) : this ()
329                         {
330                                 if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 3))
331                                         throw new ArgumentException ("Invalid EnvelopedData");
332
333                                 if (asn1[0][0].Tag != 0x02)
334                                         throw new ArgumentException ("Invalid version");
335                                 _version = asn1[0][0].Value[0];
336
337                                 // recipientInfos
338
339                                 ASN1 recipientInfos = asn1 [0][1];
340                                 if (recipientInfos.Tag != 0x31)
341                                         throw new ArgumentException ("missing RecipientInfos");
342                                 for (int i=0; i < recipientInfos.Count; i++) {
343                                         ASN1 recipientInfo = recipientInfos [i];
344                                         _recipientInfos.Add (new RecipientInfo (recipientInfo));
345                                 }
346
347                                 ASN1 encryptedContentInfo = asn1[0][2];
348                                 if (encryptedContentInfo.Tag != 0x30)
349                                         throw new ArgumentException ("missing EncryptedContentInfo");
350
351                                 ASN1 contentType = encryptedContentInfo [0];
352                                 if (contentType.Tag != 0x06)
353                                         throw new ArgumentException ("missing EncryptedContentInfo.ContentType");
354                                 _content = new ContentInfo (ASN1Convert.ToOid (contentType));
355
356                                 ASN1 contentEncryptionAlgorithm = encryptedContentInfo [1];
357                                 if (contentEncryptionAlgorithm.Tag != 0x30)
358                                         throw new ArgumentException ("missing EncryptedContentInfo.ContentEncryptionAlgorithmIdentifier");
359                                 _encryptionAlgorithm = new ContentInfo (ASN1Convert.ToOid (contentEncryptionAlgorithm [0]));
360                                 _encryptionAlgorithm.Content = contentEncryptionAlgorithm [1];
361                                 
362                                 ASN1 encryptedContent = encryptedContentInfo [2];
363                                 if (encryptedContent.Tag != 0x80)
364                                         throw new ArgumentException ("missing EncryptedContentInfo.EncryptedContent");
365                                 _encrypted = encryptedContent.Value;
366                         }
367
368                         public ArrayList RecipientInfos {
369                                   get { return _recipientInfos; }
370                         }
371
372                         public ASN1 ASN1 {
373                                 get { return GetASN1(); }
374                         }
375
376                         public ContentInfo ContentInfo {
377                                 get { return _content; }
378                         }
379
380                         public ContentInfo EncryptionAlgorithm {
381                                 get { return _encryptionAlgorithm; }
382                         }
383
384                         public byte[] EncryptedContent {
385                                 get { 
386                                         if (_encrypted == null)
387                                                 return null;
388                                         return (byte[]) _encrypted.Clone ();
389                                 }
390                         }
391
392                         public byte Version {
393                                 get { return _version; }
394                                 set { _version = value; }
395                         }
396
397                         internal ASN1 GetASN1 () 
398                         {
399                                 // SignedData ::= SEQUENCE {
400                                 ASN1 signedData = new ASN1 (0x30);
401                                 // version Version -> Version ::= INTEGER
402 /*                              byte[] ver = { _version };
403                                 signedData.Add (new ASN1 (0x02, ver));
404                                 // digestAlgorithms DigestAlgorithmIdentifiers -> DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
405                                 ASN1 digestAlgorithms = signedData.Add (new ASN1 (0x31));
406                                 if (hashAlgorithm != null) {
407                                         string hashOid = CryptoConfig.MapNameToOid (hashAlgorithm);
408                                         digestAlgorithms.Add (AlgorithmIdentifier (hashOid));
409                                 }
410
411                                 // contentInfo ContentInfo,
412                                 ASN1 ci = contentInfo.ASN1;
413                                 signedData.Add (ci);
414                                 if ((mda == null) && (hashAlgorithm != null)) {
415                                         // automatically add the messageDigest authenticated attribute
416                                         HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
417                                         byte[] idcHash = ha.ComputeHash (ci[1][0].Value);
418                                         ASN1 md = new ASN1 (0x30);
419                                         mda = Attribute (messageDigest, md.Add (new ASN1 (0x04, idcHash)));
420                                         signerInfo.AuthenticatedAttributes.Add (mda);
421                                 }
422
423                                 // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
424                                 if (certs.Count > 0) {
425                                         ASN1 a0 = signedData.Add (new ASN1 (0xA0));
426                                         foreach (X509Certificate x in certs)
427                                                 a0.Add (new ASN1 (x.RawData));
428                                 }
429                                 // crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
430                                 if (crls.Count > 0) {
431                                         ASN1 a1 = signedData.Add (new ASN1 (0xA1));
432                                         foreach (byte[] crl in crls)
433                                                 a1.Add (new ASN1 (crl));
434                                 }
435                                 // signerInfos SignerInfos -> SignerInfos ::= SET OF SignerInfo
436                                 ASN1 signerInfos = signedData.Add (new ASN1 (0x31));
437                                 if (signerInfo.Key != null)
438                                         signerInfos.Add (signerInfo.ASN1);*/
439                                 return signedData;
440                         }
441
442                         public byte[] GetBytes () {
443                                 return GetASN1 ().GetBytes ();
444                         }
445                 }
446
447                 /* RecipientInfo ::= SEQUENCE {
448                  *      version Version,
449                  *      issuerAndSerialNumber IssuerAndSerialNumber,
450                  *      keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
451                  *      encryptedKey EncryptedKey 
452                  * }
453                  * 
454                  * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
455                  * 
456                  * EncryptedKey ::= OCTET STRING
457                  */
458                 public class RecipientInfo {
459
460                         private int _version;
461                         private string _oid;
462                         private byte[] _key;
463                         private byte[] _ski;
464                         private string _issuer;
465                         private byte[] _serial;
466
467                         public RecipientInfo () {}
468
469                         public RecipientInfo (ASN1 data) 
470                         {
471                                 if (data.Tag != 0x30)
472                                         throw new ArgumentException ("Invalid RecipientInfo");
473                                 
474                                 ASN1 version = data [0];
475                                 if (version.Tag != 0x02)
476                                         throw new ArgumentException ("missing Version");
477                                 _version = version.Value [0];
478
479                                 // issuerAndSerialNumber IssuerAndSerialNumber
480                                 ASN1 subjectIdentifierType = data [1];
481                                 if ((subjectIdentifierType.Tag == 0x80) && (_version == 3)) {
482                                         _ski = subjectIdentifierType.Value;
483                                 }
484                                 else {
485                                         _issuer = X501.ToString (subjectIdentifierType [0]);
486                                         _serial = subjectIdentifierType [1].Value;
487                                 }
488
489                                 ASN1 keyEncryptionAlgorithm = data [2];
490                                 _oid = ASN1Convert.ToOid (keyEncryptionAlgorithm [0]);
491
492                                 ASN1 encryptedKey = data [3];
493                                 _key = encryptedKey.Value;
494                         }
495
496                         public string Oid {
497                                 get { return _oid; }
498                         }
499
500                         public byte[] Key {
501                                 get { 
502                                         if (_key == null)
503                                                 return null;
504                                         return (byte[]) _key.Clone ();
505                                 }
506                         }
507
508                         public byte[] SubjectKeyIdentifier {
509                                 get { 
510                                         if (_ski == null)
511                                                 return null;
512                                         return (byte[]) _ski.Clone ();
513                                 }
514                         }
515
516                         public string Issuer {
517                                 get { return _issuer; }
518                         }
519
520                         public byte[] Serial {
521                                 get { 
522                                         if (_serial == null)
523                                                 return null;
524                                         return (byte[]) _serial.Clone ();
525                                 }
526                         }
527
528                         public int Version {
529                                 get { return _version; }
530                         }
531                 }
532
533                 /*
534                  * SignedData ::= SEQUENCE {
535                  *      version Version,
536                  *      digestAlgorithms DigestAlgorithmIdentifiers,
537                  *      contentInfo ContentInfo,
538                  *      certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
539                  *      crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
540                  *      signerInfos SignerInfos 
541                  * }
542                  */
543                 public class SignedData {
544                         private byte version;
545                         private string hashAlgorithm;
546                         private ContentInfo contentInfo;
547                         private X509CertificateCollection certs;
548                         private ArrayList crls;
549                         private SignerInfo signerInfo;
550                         private bool mda;
551                         private bool signed;
552
553                         public SignedData () 
554                         {
555                                 version = 1;
556                                 contentInfo = new ContentInfo ();
557                                 certs = new X509CertificateCollection ();
558                                 crls = new ArrayList ();
559                                 signerInfo = new SignerInfo ();
560                                 mda = true;
561                                 signed = false;
562                         }
563
564                         public SignedData (byte[] data) 
565                                 : this (new ASN1 (data)) 
566                         {
567                         }
568
569                         public SignedData (ASN1 asn1) 
570                         {
571                                 if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 4))
572                                         throw new ArgumentException ("Invalid SignedData");
573
574                                 if (asn1[0][0].Tag != 0x02)
575                                         throw new ArgumentException ("Invalid version");
576                                 version = asn1[0][0].Value[0];
577
578                                 contentInfo = new ContentInfo (asn1[0][2]);
579
580                                 int n = 3;
581                                 certs = new X509CertificateCollection ();
582                                 if (asn1[0][n].Tag == 0xA0) {
583                                         for (int i=0; i < asn1[0][n].Count; i++)
584                                                 certs.Add (new X509Certificate (asn1[0][n][i].GetBytes ()));
585                                         n++;
586                                 }
587
588                                 crls = new ArrayList ();
589                                 if (asn1[0][n].Tag == 0xA1) {
590                                         for (int i=0; i < asn1[0][n].Count; i++)
591                                                 crls.Add (asn1[0][n][i].GetBytes ());
592                                         n++;
593                                 }
594
595                                 if (asn1[0][n].Count > 0)
596                                         signerInfo = new SignerInfo (asn1[0][n]);
597                                 else
598                                         signerInfo = new SignerInfo ();
599
600                                 // Exchange hash algorithm Oid from SignerInfo
601                                 if (signerInfo.HashName != null) {
602                                         HashName = OidToName(signerInfo.HashName);
603                                 }
604                                 
605                                 // Check if SignerInfo has authenticated attributes
606                                 mda = (signerInfo.AuthenticatedAttributes.Count > 0);
607                         }
608
609                         public ASN1 ASN1 {
610                                 get { return GetASN1(); }
611                         }
612
613                         public X509CertificateCollection Certificates {
614                                 get { return certs; }
615                         }
616
617                         public ContentInfo ContentInfo {
618                                 get { return contentInfo; }
619                         }
620
621                         public ArrayList Crls {
622                                 get { return crls; }
623                         }
624
625                         public string HashName {
626                                 get { return hashAlgorithm; }
627                                 // todo add validation
628                                 set { 
629                                         hashAlgorithm = value; 
630                                         signerInfo.HashName = value;
631                                 }
632                         }
633
634                         public SignerInfo SignerInfo {
635                                 get { return signerInfo; }
636                         }
637
638                         public byte Version {
639                                 get { return version; }
640                                 set { version = value; }
641                         }
642
643                         public bool UseAuthenticatedAttributes {
644                                 get { return mda; }
645                                 set { mda = value; }
646                         }
647
648                         public bool VerifySignature (AsymmetricAlgorithm aa)
649                         {
650                                 if (aa == null) {
651                                         return false;
652                                 }
653
654                                 RSAPKCS1SignatureDeformatter r = new RSAPKCS1SignatureDeformatter (aa);
655                                 r.SetHashAlgorithm (hashAlgorithm);
656                                 HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
657
658                                 byte[] signature = signerInfo.Signature;
659                                 byte[] hash = null;
660
661                                 if (mda) {
662                                         ASN1 asn = new ASN1 (0x31);
663                                         foreach (ASN1 attr in signerInfo.AuthenticatedAttributes)
664                                                 asn.Add (attr);
665
666                                         hash = ha.ComputeHash (asn.GetBytes ());
667                                 } else {
668                                         hash = ha.ComputeHash (contentInfo.Content[0].Value);
669                                 }
670
671                                 if (hash != null && signature != null) {
672                                         return r.VerifySignature (hash, signature);
673                                 }
674                                 return false;
675                         }
676
677                         internal string OidToName (string oid)
678                         {
679                                 switch (oid) {
680                                 case "1.3.14.3.2.26" :
681                                         return "SHA1";
682                                 case "1.2.840.113549.2.2" :
683                                         return "MD2";
684                                 case "1.2.840.113549.2.5" :
685                                         return "MD5";
686                                 case "2.16.840.1.101.3.4.1" :
687                                         return "SHA256";
688                                 case "2.16.840.1.101.3.4.2" :
689                                         return "SHA384";
690                                 case "2.16.840.1.101.3.4.3" :
691                                         return "SHA512";
692                                 default :
693                                         break;
694                                 }
695                                 // Unknown Oid
696                                 return oid;
697                         }
698
699                         internal ASN1 GetASN1 () 
700                         {
701                                 // SignedData ::= SEQUENCE {
702                                 ASN1 signedData = new ASN1 (0x30);
703                                 // version Version -> Version ::= INTEGER
704                                 byte[] ver = { version };
705                                 signedData.Add (new ASN1 (0x02, ver));
706                                 // digestAlgorithms DigestAlgorithmIdentifiers -> DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
707                                 ASN1 digestAlgorithms = signedData.Add (new ASN1 (0x31));
708                                 if (hashAlgorithm != null) {
709                                         string hashOid = CryptoConfig.MapNameToOID (hashAlgorithm);
710                                         digestAlgorithms.Add (AlgorithmIdentifier (hashOid));
711                                 }
712
713                                 // contentInfo ContentInfo,
714                                 ASN1 ci = contentInfo.ASN1;
715                                 signedData.Add (ci);
716                                 if (!signed && (hashAlgorithm != null)) {
717                                         if (mda) {
718                                                 // Use authenticated attributes for signature
719                                                 
720                                                 // Automatically add the contentType authenticated attribute
721                                                 ASN1 ctattr = Attribute (Oid.contentType, ci[0]);
722                                                 signerInfo.AuthenticatedAttributes.Add (ctattr);
723                                                 
724                                                 // Automatically add the messageDigest authenticated attribute
725                                                 HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
726                                                 byte[] idcHash = ha.ComputeHash (ci[1][0].Value);
727                                                 ASN1 md = new ASN1 (0x30);
728                                                 ASN1 mdattr = Attribute (Oid.messageDigest, md.Add (new ASN1 (0x04, idcHash)));
729                                                 signerInfo.AuthenticatedAttributes.Add (mdattr);
730                                         } else {
731                                                 // Don't use authenticated attributes for signature -- signature is content
732                                                 RSAPKCS1SignatureFormatter r = new RSAPKCS1SignatureFormatter (signerInfo.Key);
733                                                 r.SetHashAlgorithm (hashAlgorithm);
734                                                 HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
735                                                 byte[] sig = ha.ComputeHash (ci[1][0].Value);
736                                                 signerInfo.Signature = r.CreateSignature (sig);
737                                         }
738                                         signed = true;
739                                 }
740
741                                 // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
742                                 if (certs.Count > 0) {
743                                         ASN1 a0 = signedData.Add (new ASN1 (0xA0));
744                                         foreach (X509Certificate x in certs)
745                                                 a0.Add (new ASN1 (x.RawData));
746                                 }
747                                 // crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
748                                 if (crls.Count > 0) {
749                                         ASN1 a1 = signedData.Add (new ASN1 (0xA1));
750                                         foreach (byte[] crl in crls)
751                                                 a1.Add (new ASN1 (crl));
752                                 }
753                                 // signerInfos SignerInfos -> SignerInfos ::= SET OF SignerInfo
754                                 ASN1 signerInfos = signedData.Add (new ASN1 (0x31));
755                                 if (signerInfo.Key != null)
756                                         signerInfos.Add (signerInfo.ASN1);
757                                 return signedData;
758                         }
759
760                         public byte[] GetBytes () 
761                         {
762                                 return GetASN1 ().GetBytes ();
763                         }
764                 }
765
766                 /*
767                  * SignerInfo ::= SEQUENCE {
768                  *      version Version,
769                  *      issuerAndSerialNumber IssuerAndSerialNumber,
770                  *      digestAlgorithm DigestAlgorithmIdentifier,
771                  *      authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
772                  *      digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
773                  *      encryptedDigest EncryptedDigest,
774                  *      unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL 
775                  * }
776                  * 
777                  * For version == 3 issuerAndSerialNumber may be replaced by ...
778                  */
779                 public class SignerInfo {
780
781                         private byte version;
782                         private X509Certificate x509;
783                         private string hashAlgorithm;
784                         private AsymmetricAlgorithm key;
785                         private ArrayList authenticatedAttributes;
786                         private ArrayList unauthenticatedAttributes;
787                         private byte[] signature;
788                         private string issuer;
789                         private byte[] serial;
790                         private byte[] ski;
791
792                         public SignerInfo () 
793                         {
794                                 version = 1;
795                                 authenticatedAttributes = new ArrayList ();
796                                 unauthenticatedAttributes = new ArrayList ();
797                         }
798
799                         public SignerInfo (byte[] data) 
800                                 : this (new ASN1 (data)) {}
801
802                         // TODO: INCOMPLETE
803                         public SignerInfo (ASN1 asn1) : this () 
804                         {
805                                 if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 5))
806                                         throw new ArgumentException ("Invalid SignedData");
807
808                                 // version Version
809                                 if (asn1[0][0].Tag != 0x02)
810                                         throw new ArgumentException ("Invalid version");
811                                 version = asn1[0][0].Value[0];
812
813                                 // issuerAndSerialNumber IssuerAndSerialNumber
814                                 ASN1 subjectIdentifierType = asn1 [0][1];
815                                 if ((subjectIdentifierType.Tag == 0x80) && (version == 3)) {
816                                         ski = subjectIdentifierType.Value;
817                                 }
818                                 else {
819                                         issuer = X501.ToString (subjectIdentifierType [0]);
820                                         serial = subjectIdentifierType [1].Value;
821                                 }
822
823                                 // digestAlgorithm DigestAlgorithmIdentifier
824                                 ASN1 digestAlgorithm = asn1 [0][2];
825                                 hashAlgorithm = ASN1Convert.ToOid (digestAlgorithm [0]);
826
827                                 // authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL
828                                 int n = 3;
829                                 ASN1 authAttributes = asn1 [0][n];
830                                 if (authAttributes.Tag == 0xA0) {
831                                         n++;
832                                         for (int i=0; i < authAttributes.Count; i++)
833                                                 authenticatedAttributes.Add (authAttributes [i]);
834                                 }
835
836                                 // digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier
837                                 n++;
838                                 // ASN1 digestEncryptionAlgorithm = asn1 [0][n++];
839                                 // string digestEncryptionAlgorithmOid = ASN1Convert.ToOid (digestEncryptionAlgorithm [0]);
840
841                                 // encryptedDigest EncryptedDigest
842                                 ASN1 encryptedDigest = asn1 [0][n++];
843                                 if (encryptedDigest.Tag == 0x04)
844                                         signature = encryptedDigest.Value;
845
846                                 // unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
847                                 ASN1 unauthAttributes = asn1 [0][n];
848                                 if ((unauthAttributes != null) && (unauthAttributes.Tag == 0xA1)) {
849                                         for (int i=0; i < unauthAttributes.Count; i++)
850                                                 unauthenticatedAttributes.Add (unauthAttributes [i]);
851                                 }
852                         }
853
854                         public string IssuerName {
855                                 get { return issuer; }
856                         }
857
858                         public byte[] SerialNumber {
859                                 get { 
860                                         if (serial == null)
861                                                 return null;
862                                         return (byte[]) serial.Clone (); 
863                                 }
864                         }
865
866                         public byte[] SubjectKeyIdentifier {
867                                 get { 
868                                         if (ski == null)
869                                                 return null;
870                                         return (byte[]) ski.Clone (); 
871                                 }
872                         }
873
874                         public ASN1 ASN1 {
875                                 get { return GetASN1(); }
876                         }
877
878                         public ArrayList AuthenticatedAttributes {
879                                 get { return authenticatedAttributes; }
880                         }
881
882                         public X509Certificate Certificate {
883                                 get { return x509; }
884                                 set { x509 = value; }
885                         }
886
887                         public string HashName {
888                                 get { return hashAlgorithm; }
889                                 set { hashAlgorithm = value; }
890                         }
891
892                         public AsymmetricAlgorithm Key {
893                                 get { return key; }
894                                 set { key = value; }
895                         }
896
897                         public byte[] Signature {
898                                 get { 
899                                         if (signature == null)
900                                                 return null;
901                                         return (byte[]) signature.Clone (); 
902                                 }
903
904                                 set {
905                                         if (value != null) {
906                                                 signature = (byte[]) value.Clone ();
907                                         }
908                                 }
909                         }
910
911                         public ArrayList UnauthenticatedAttributes {
912                                 get { return unauthenticatedAttributes; }
913                         }
914
915                         public byte Version {
916                                 get { return version; }
917                                 set { version = value; }
918                         }
919
920                         internal ASN1 GetASN1 () 
921                         {
922                                 if ((key == null) || (hashAlgorithm == null))
923                                         return null;
924                                 byte[] ver = { version };
925                                 ASN1 signerInfo = new ASN1 (0x30);
926                                 // version Version -> Version ::= INTEGER
927                                 signerInfo.Add (new ASN1 (0x02, ver));
928                                 // issuerAndSerialNumber IssuerAndSerialNumber,
929                                 signerInfo.Add (PKCS7.IssuerAndSerialNumber (x509));
930                                 // digestAlgorithm DigestAlgorithmIdentifier,
931                                 string hashOid = CryptoConfig.MapNameToOID (hashAlgorithm);
932                                 signerInfo.Add (AlgorithmIdentifier (hashOid));
933                                 // authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
934                                 ASN1 aa = null;
935                                 if (authenticatedAttributes.Count > 0) {
936                                         aa = signerInfo.Add (new ASN1 (0xA0));
937                                         authenticatedAttributes.Sort(new SortedSet ());
938                                         foreach (ASN1 attr in authenticatedAttributes)
939                                                 aa.Add (attr);
940                                 }
941                                 // digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
942                                 if (key is RSA) {
943                                         signerInfo.Add (AlgorithmIdentifier (PKCS7.Oid.rsaEncryption));
944
945                                         if (aa != null) {
946                                                 // Calculate the signature here; otherwise it must be set from SignedData
947                                                 RSAPKCS1SignatureFormatter r = new RSAPKCS1SignatureFormatter (key);
948                                                 r.SetHashAlgorithm (hashAlgorithm);
949                                                 byte[] tbs = aa.GetBytes ();
950                                                 tbs [0] = 0x31; // not 0xA0 for signature
951                                                 HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
952                                                 byte[] tbsHash = ha.ComputeHash (tbs);
953                                                 signature = r.CreateSignature (tbsHash);
954                                         }
955                                 }
956                                 else if (key is DSA) {
957                                         throw new NotImplementedException ("not yet");
958                                 }
959                                 else
960                                         throw new CryptographicException ("Unknown assymetric algorithm");
961                                 // encryptedDigest EncryptedDigest,
962                                 signerInfo.Add (new ASN1 (0x04, signature));
963                                 // unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL 
964                                 if (unauthenticatedAttributes.Count > 0) {
965                                         ASN1 ua = signerInfo.Add (new ASN1 (0xA1));
966                                         unauthenticatedAttributes.Sort(new SortedSet ());
967                                         foreach (ASN1 attr in unauthenticatedAttributes)
968                                                 ua.Add (attr);
969                                 }
970                                 return signerInfo;
971                         }
972
973                         public byte[] GetBytes () 
974                         {
975                                 return GetASN1 ().GetBytes ();
976                         }
977                 }
978
979                 internal class SortedSet : IComparer {
980
981                         public int Compare (object x, object y)
982                         {
983                                 if (x == null)
984                                         return (y == null) ? 0 : -1;
985                                 else if (y == null)
986                                         return 1;
987
988                                 ASN1 xx = x as ASN1;
989                                 ASN1 yy = y as ASN1;
990                                 
991                                 if ((xx == null) || (yy == null)) {
992                                         throw new ArgumentException (Locale.GetText ("Invalid objects."));
993                                 }
994
995                                 byte[] xb = xx.GetBytes ();
996                                 byte[] yb = yy.GetBytes ();
997
998                                 for (int i = 0; i < xb.Length; i++) {
999                                         if (i == yb.Length)
1000                                                 break;
1001
1002                                         if (xb[i] == yb[i]) 
1003                                                 continue;
1004                                                 
1005                                         return (xb[i] < yb[i]) ? -1 : 1; 
1006                                 }
1007
1008                                 // The arrays are equal up to the shortest of them.
1009                                 if (xb.Length > yb.Length)
1010                                         return 1;
1011                                 else if (xb.Length < yb.Length)
1012                                         return -1;
1013
1014                                 return 0;
1015                         }
1016                 }
1017         }
1018 }