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