(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / Mono.Security / Mono.Security / PKCS7.cs
blob3cdbb6fe4eb8bbc3157f2641aa8d2e5dd48bf351
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)
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.
31 using System;
32 using System.Collections;
33 using System.Security.Cryptography;
35 using Mono.Security.X509;
37 namespace Mono.Security {
39 #if INSIDE_CORLIB
40 internal
41 #else
42 public
43 #endif
44 sealed class PKCS7 {
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";
62 public Oid ()
67 private PKCS7 ()
71 static public ASN1 Attribute (string oid, ASN1 value)
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;
80 static public ASN1 AlgorithmIdentifier (string oid)
82 ASN1 ai = new ASN1 (0x30);
83 ai.Add (ASN1Convert.FromOid (oid));
84 ai.Add (new ASN1 (0x05)); // NULL
85 return ai;
88 static public ASN1 AlgorithmIdentifier (string oid, ASN1 parameters)
90 ASN1 ai = new ASN1 (0x30);
91 ai.Add (ASN1Convert.FromOid (oid));
92 ai.Add (parameters);
93 return ai;
97 * IssuerAndSerialNumber ::= SEQUENCE {
98 * issuer Name,
99 * serialNumber CertificateSerialNumber
102 static public ASN1 IssuerAndSerialNumber (X509Certificate x509)
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;
118 flag = true;
121 ASN1 iasn = new ASN1 (0x30);
122 iasn.Add (issuer);
123 iasn.Add (serial);
124 return iasn;
128 * ContentInfo ::= SEQUENCE {
129 * contentType ContentType,
130 * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
132 * ContentType ::= OBJECT IDENTIFIER
134 public class ContentInfo {
136 private string contentType;
137 private ASN1 content;
139 public ContentInfo ()
141 content = new ASN1 (0xA0);
144 public ContentInfo (string oid) : this ()
146 contentType = oid;
149 public ContentInfo (byte[] data)
150 : this (new ASN1 (data)) {}
152 public ContentInfo (ASN1 asn1)
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];
167 public ASN1 ASN1 {
168 get { return GetASN1(); }
171 public ASN1 Content {
172 get { return content; }
173 set { content = value; }
176 public string ContentType {
177 get { return contentType; }
178 set { contentType = value; }
181 internal ASN1 GetASN1 ()
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;
193 public byte[] GetBytes ()
195 return GetASN1 ().GetBytes ();
200 * EncryptedData ::= SEQUENCE {
201 * version INTEGER {edVer0(0)} (edVer0),
202 * encryptedContentInfo EncryptedContentInfo
205 public class EncryptedData {
206 private byte _version;
207 private ContentInfo _content;
208 private ContentInfo _encryptionAlgorithm;
209 private byte[] _encrypted;
211 public EncryptedData ()
213 _version = 0;
216 public EncryptedData (byte[] data)
217 : this (new ASN1 (data))
221 public EncryptedData (ASN1 asn1) : this ()
223 if ((asn1.Tag != 0x30) || (asn1.Count < 2))
224 throw new ArgumentException ("Invalid EncryptedData");
226 if (asn1 [0].Tag != 0x02)
227 throw new ArgumentException ("Invalid version");
228 _version = asn1 [0].Value [0];
230 ASN1 encryptedContentInfo = asn1 [1];
231 if (encryptedContentInfo.Tag != 0x30)
232 throw new ArgumentException ("missing EncryptedContentInfo");
234 ASN1 contentType = encryptedContentInfo [0];
235 if (contentType.Tag != 0x06)
236 throw new ArgumentException ("missing EncryptedContentInfo.ContentType");
237 _content = new ContentInfo (ASN1Convert.ToOid (contentType));
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];
245 ASN1 encryptedContent = encryptedContentInfo [2];
246 if (encryptedContent.Tag != 0x80)
247 throw new ArgumentException ("missing EncryptedContentInfo.EncryptedContent");
248 _encrypted = encryptedContent.Value;
251 public ASN1 ASN1 {
252 get { return GetASN1(); }
255 public ContentInfo ContentInfo {
256 get { return _content; }
259 public ContentInfo EncryptionAlgorithm {
260 get { return _encryptionAlgorithm; }
263 public byte[] EncryptedContent {
264 get {
265 if (_encrypted == null)
266 return null;
267 return (byte[]) _encrypted.Clone ();
271 public byte Version {
272 get { return _version; }
273 set { _version = value; }
276 // methods
278 internal ASN1 GetASN1 ()
280 return null;
283 public byte[] GetBytes ()
285 return GetASN1 ().GetBytes ();
290 * EnvelopedData ::= SEQUENCE {
291 * version Version,
292 * recipientInfos RecipientInfos,
293 * encryptedContentInfo EncryptedContentInfo
296 * RecipientInfos ::= SET OF RecipientInfo
298 * EncryptedContentInfo ::= SEQUENCE {
299 * contentType ContentType,
300 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
301 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
304 * EncryptedContent ::= OCTET STRING
307 public class EnvelopedData {
308 private byte _version;
309 private ContentInfo _content;
310 private ContentInfo _encryptionAlgorithm;
311 private ArrayList _recipientInfos;
312 private byte[] _encrypted;
314 public EnvelopedData ()
316 _version = 0;
317 _content = new ContentInfo ();
318 _encryptionAlgorithm = new ContentInfo ();
319 _recipientInfos = new ArrayList ();
322 public EnvelopedData (byte[] data)
323 : this (new ASN1 (data))
327 public EnvelopedData (ASN1 asn1) : this ()
329 if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 3))
330 throw new ArgumentException ("Invalid EnvelopedData");
332 if (asn1[0][0].Tag != 0x02)
333 throw new ArgumentException ("Invalid version");
334 _version = asn1[0][0].Value[0];
336 // recipientInfos
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));
346 ASN1 encryptedContentInfo = asn1[0][2];
347 if (encryptedContentInfo.Tag != 0x30)
348 throw new ArgumentException ("missing EncryptedContentInfo");
350 ASN1 contentType = encryptedContentInfo [0];
351 if (contentType.Tag != 0x06)
352 throw new ArgumentException ("missing EncryptedContentInfo.ContentType");
353 _content = new ContentInfo (ASN1Convert.ToOid (contentType));
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];
361 ASN1 encryptedContent = encryptedContentInfo [2];
362 if (encryptedContent.Tag != 0x80)
363 throw new ArgumentException ("missing EncryptedContentInfo.EncryptedContent");
364 _encrypted = encryptedContent.Value;
367 public ArrayList RecipientInfos {
368 get { return _recipientInfos; }
371 public ASN1 ASN1 {
372 get { return GetASN1(); }
375 public ContentInfo ContentInfo {
376 get { return _content; }
379 public ContentInfo EncryptionAlgorithm {
380 get { return _encryptionAlgorithm; }
383 public byte[] EncryptedContent {
384 get {
385 if (_encrypted == null)
386 return null;
387 return (byte[]) _encrypted.Clone ();
391 public byte Version {
392 get { return _version; }
393 set { _version = value; }
396 internal ASN1 GetASN1 ()
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));
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);
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));
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));
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;
441 public byte[] GetBytes () {
442 return GetASN1 ().GetBytes ();
446 /* RecipientInfo ::= SEQUENCE {
447 * version Version,
448 * issuerAndSerialNumber IssuerAndSerialNumber,
449 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
450 * encryptedKey EncryptedKey
453 * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
455 * EncryptedKey ::= OCTET STRING
457 public class RecipientInfo {
459 private int _version;
460 private string _oid;
461 private byte[] _key;
462 private byte[] _ski;
463 private string _issuer;
464 private byte[] _serial;
466 public RecipientInfo () {}
468 public RecipientInfo (ASN1 data)
470 if (data.Tag != 0x30)
471 throw new ArgumentException ("Invalid RecipientInfo");
473 ASN1 version = data [0];
474 if (version.Tag != 0x02)
475 throw new ArgumentException ("missing Version");
476 _version = version.Value [0];
478 // issuerAndSerialNumber IssuerAndSerialNumber
479 ASN1 subjectIdentifierType = data [1];
480 if ((subjectIdentifierType.Tag == 0x80) && (_version == 3)) {
481 _ski = subjectIdentifierType.Value;
483 else {
484 _issuer = X501.ToString (subjectIdentifierType [0]);
485 _serial = subjectIdentifierType [1].Value;
488 ASN1 keyEncryptionAlgorithm = data [2];
489 _oid = ASN1Convert.ToOid (keyEncryptionAlgorithm [0]);
491 ASN1 encryptedKey = data [3];
492 _key = encryptedKey.Value;
495 public string Oid {
496 get { return _oid; }
499 public byte[] Key {
500 get {
501 if (_key == null)
502 return null;
503 return (byte[]) _key.Clone ();
507 public byte[] SubjectKeyIdentifier {
508 get {
509 if (_ski == null)
510 return null;
511 return (byte[]) _ski.Clone ();
515 public string Issuer {
516 get { return _issuer; }
519 public byte[] Serial {
520 get {
521 if (_serial == null)
522 return null;
523 return (byte[]) _serial.Clone ();
527 public int Version {
528 get { return _version; }
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
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;
552 public SignedData ()
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;
563 public SignedData (byte[] data)
564 : this (new ASN1 (data))
568 public SignedData (ASN1 asn1)
570 if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 4))
571 throw new ArgumentException ("Invalid SignedData");
573 if (asn1[0][0].Tag != 0x02)
574 throw new ArgumentException ("Invalid version");
575 version = asn1[0][0].Value[0];
577 contentInfo = new ContentInfo (asn1[0][2]);
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++;
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++;
594 if (asn1[0][n].Count > 0)
595 signerInfo = new SignerInfo (asn1[0][n]);
596 else
597 signerInfo = new SignerInfo ();
599 // Exchange hash algorithm Oid from SignerInfo
600 if (signerInfo.HashName != null) {
601 HashName = OidToName(signerInfo.HashName);
604 // Check if SignerInfo has authenticated attributes
605 mda = (signerInfo.AuthenticatedAttributes.Count > 0);
608 public ASN1 ASN1 {
609 get { return GetASN1(); }
612 public X509CertificateCollection Certificates {
613 get { return certs; }
616 public ContentInfo ContentInfo {
617 get { return contentInfo; }
620 public ArrayList Crls {
621 get { return crls; }
624 public string HashName {
625 get { return hashAlgorithm; }
626 // todo add validation
627 set {
628 hashAlgorithm = value;
629 signerInfo.HashName = value;
633 public SignerInfo SignerInfo {
634 get { return signerInfo; }
637 public byte Version {
638 get { return version; }
639 set { version = value; }
642 public bool UseAuthenticatedAttributes {
643 get { return mda; }
644 set { mda = value; }
647 public bool VerifySignature (AsymmetricAlgorithm aa)
649 if (aa == null) {
650 return false;
653 RSAPKCS1SignatureDeformatter r = new RSAPKCS1SignatureDeformatter (aa);
654 r.SetHashAlgorithm (hashAlgorithm);
655 HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
657 byte[] signature = signerInfo.Signature;
658 byte[] hash = null;
660 if (mda) {
661 ASN1 asn = new ASN1 (0x31);
662 foreach (ASN1 attr in signerInfo.AuthenticatedAttributes)
663 asn.Add (attr);
665 hash = ha.ComputeHash (asn.GetBytes ());
666 } else {
667 hash = ha.ComputeHash (contentInfo.Content[0].Value);
670 if (hash != null && signature != null) {
671 return r.VerifySignature (hash, signature);
673 return false;
676 internal string OidToName (string oid)
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;
694 // Unknown Oid
695 return oid;
698 internal ASN1 GetASN1 ()
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));
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
719 // Automatically add the contentType authenticated attribute
720 ASN1 ctattr = Attribute (Oid.contentType, ci[0]);
721 signerInfo.AuthenticatedAttributes.Add (ctattr);
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);
737 signed = true;
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));
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));
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;
759 public byte[] GetBytes ()
761 return GetASN1 ().GetBytes ();
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
776 * For version == 3 issuerAndSerialNumber may be replaced by ...
778 public class SignerInfo {
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;
791 public SignerInfo ()
793 version = 1;
794 authenticatedAttributes = new ArrayList ();
795 unauthenticatedAttributes = new ArrayList ();
798 public SignerInfo (byte[] data)
799 : this (new ASN1 (data)) {}
801 // TODO: INCOMPLETE
802 public SignerInfo (ASN1 asn1) : this ()
804 if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 5))
805 throw new ArgumentException ("Invalid SignedData");
807 // version Version
808 if (asn1[0][0].Tag != 0x02)
809 throw new ArgumentException ("Invalid version");
810 version = asn1[0][0].Value[0];
812 // issuerAndSerialNumber IssuerAndSerialNumber
813 ASN1 subjectIdentifierType = asn1 [0][1];
814 if ((subjectIdentifierType.Tag == 0x80) && (version == 3)) {
815 ski = subjectIdentifierType.Value;
817 else {
818 issuer = X501.ToString (subjectIdentifierType [0]);
819 serial = subjectIdentifierType [1].Value;
822 // digestAlgorithm DigestAlgorithmIdentifier
823 ASN1 digestAlgorithm = asn1 [0][2];
824 hashAlgorithm = ASN1Convert.ToOid (digestAlgorithm [0]);
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]);
835 // digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier
836 n++;
837 // ASN1 digestEncryptionAlgorithm = asn1 [0][n++];
838 // string digestEncryptionAlgorithmOid = ASN1Convert.ToOid (digestEncryptionAlgorithm [0]);
840 // encryptedDigest EncryptedDigest
841 ASN1 encryptedDigest = asn1 [0][n++];
842 if (encryptedDigest.Tag == 0x04)
843 signature = encryptedDigest.Value;
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]);
853 public string IssuerName {
854 get { return issuer; }
857 public byte[] SerialNumber {
858 get {
859 if (serial == null)
860 return null;
861 return (byte[]) serial.Clone ();
865 public byte[] SubjectKeyIdentifier {
866 get {
867 if (ski == null)
868 return null;
869 return (byte[]) ski.Clone ();
873 public ASN1 ASN1 {
874 get { return GetASN1(); }
877 public ArrayList AuthenticatedAttributes {
878 get { return authenticatedAttributes; }
881 public X509Certificate Certificate {
882 get { return x509; }
883 set { x509 = value; }
886 public string HashName {
887 get { return hashAlgorithm; }
888 set { hashAlgorithm = value; }
891 public AsymmetricAlgorithm Key {
892 get { return key; }
893 set { key = value; }
896 public byte[] Signature {
897 get {
898 if (signature == null)
899 return null;
900 return (byte[]) signature.Clone ();
903 set {
904 if (value != null) {
905 signature = (byte[]) value.Clone ();
910 public ArrayList UnauthenticatedAttributes {
911 get { return unauthenticatedAttributes; }
914 public byte Version {
915 get { return version; }
916 set { version = value; }
919 internal ASN1 GetASN1 ()
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);
939 // digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
940 if (key is RSA) {
941 signerInfo.Add (AlgorithmIdentifier (PKCS7.Oid.rsaEncryption));
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);
954 else if (key is DSA) {
955 throw new NotImplementedException ("not yet");
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);
967 return signerInfo;
970 public byte[] GetBytes ()
972 return GetASN1 ().GetBytes ();