2 // PKCS7.cs: PKCS #7 - Cryptographic Message Syntax Standard
3 // http://www.rsasecurity.com/rsalabs/pkcs/pkcs-7/index.html
6 // Sebastien Pouliot <sebastien@ximian.com>
7 // Daniel Granath <dgranath#gmail.com>
9 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
10 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
33 using System.Collections;
34 using System.Security.Cryptography;
36 using Mono.Security.X509;
38 namespace Mono.Security {
49 public const string rsaEncryption = "1.2.840.113549.1.1.1";
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";
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";
72 static public ASN1 Attribute (string oid, ASN1 value)
74 ASN1 attr = new ASN1 (0x30);
75 attr.Add (ASN1Convert.FromOid (oid));
76 ASN1 aset = attr.Add (new ASN1 (0x31));
81 static public ASN1 AlgorithmIdentifier (string oid)
83 ASN1 ai = new ASN1 (0x30);
84 ai.Add (ASN1Convert.FromOid (oid));
85 ai.Add (new ASN1 (0x05)); // NULL
89 static public ASN1 AlgorithmIdentifier (string oid, ASN1 parameters)
91 ASN1 ai = new ASN1 (0x30);
92 ai.Add (ASN1Convert.FromOid (oid));
98 * IssuerAndSerialNumber ::= SEQUENCE {
100 * serialNumber CertificateSerialNumber
103 static public ASN1 IssuerAndSerialNumber (X509Certificate x509)
107 ASN1 cert = new ASN1 (x509.RawData);
110 while (tbs < cert[0].Count) {
111 ASN1 e = cert[0][tbs++];
114 else if (e.Tag == 0x30) {
122 ASN1 iasn = new ASN1 (0x30);
129 * ContentInfo ::= SEQUENCE {
130 * contentType ContentType,
131 * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
133 * ContentType ::= OBJECT IDENTIFIER
135 public class ContentInfo {
137 private string contentType;
138 private ASN1 content;
140 public ContentInfo ()
142 content = new ASN1 (0xA0);
145 public ContentInfo (string oid) : this ()
150 public ContentInfo (byte[] data)
151 : this (new ASN1 (data)) {}
153 public ContentInfo (ASN1 asn1)
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");
169 get { return GetASN1(); }
172 public ASN1 Content {
173 get { return content; }
174 set { content = value; }
177 public string ContentType {
178 get { return contentType; }
179 set { contentType = value; }
182 internal ASN1 GetASN1 ()
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);
194 public byte[] GetBytes ()
196 return GetASN1 ().GetBytes ();
201 * EncryptedData ::= SEQUENCE {
202 * version INTEGER {edVer0(0)} (edVer0),
203 * encryptedContentInfo EncryptedContentInfo
206 public class EncryptedData {
207 private byte _version;
208 private ContentInfo _content;
209 private ContentInfo _encryptionAlgorithm;
210 private byte[] _encrypted;
212 public EncryptedData ()
217 public EncryptedData (byte[] data)
218 : this (new ASN1 (data))
222 public EncryptedData (ASN1 asn1) : this ()
224 if ((asn1.Tag != 0x30) || (asn1.Count < 2))
225 throw new ArgumentException ("Invalid EncryptedData");
227 if (asn1 [0].Tag != 0x02)
228 throw new ArgumentException ("Invalid version");
229 _version = asn1 [0].Value [0];
231 ASN1 encryptedContentInfo = asn1 [1];
232 if (encryptedContentInfo.Tag != 0x30)
233 throw new ArgumentException ("missing EncryptedContentInfo");
235 ASN1 contentType = encryptedContentInfo [0];
236 if (contentType.Tag != 0x06)
237 throw new ArgumentException ("missing EncryptedContentInfo.ContentType");
238 _content = new ContentInfo (ASN1Convert.ToOid (contentType));
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];
246 ASN1 encryptedContent = encryptedContentInfo [2];
247 if (encryptedContent.Tag != 0x80)
248 throw new ArgumentException ("missing EncryptedContentInfo.EncryptedContent");
249 _encrypted = encryptedContent.Value;
253 get { return GetASN1(); }
256 public ContentInfo ContentInfo {
257 get { return _content; }
260 public ContentInfo EncryptionAlgorithm {
261 get { return _encryptionAlgorithm; }
264 public byte[] EncryptedContent {
266 if (_encrypted == null)
268 return (byte[]) _encrypted.Clone ();
272 public byte Version {
273 get { return _version; }
274 set { _version = value; }
279 internal ASN1 GetASN1 ()
284 public byte[] GetBytes ()
286 return GetASN1 ().GetBytes ();
291 * EnvelopedData ::= SEQUENCE {
293 * recipientInfos RecipientInfos,
294 * encryptedContentInfo EncryptedContentInfo
297 * RecipientInfos ::= SET OF RecipientInfo
299 * EncryptedContentInfo ::= SEQUENCE {
300 * contentType ContentType,
301 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
302 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
305 * EncryptedContent ::= OCTET STRING
308 public class EnvelopedData {
309 private byte _version;
310 private ContentInfo _content;
311 private ContentInfo _encryptionAlgorithm;
312 private ArrayList _recipientInfos;
313 private byte[] _encrypted;
315 public EnvelopedData ()
318 _content = new ContentInfo ();
319 _encryptionAlgorithm = new ContentInfo ();
320 _recipientInfos = new ArrayList ();
323 public EnvelopedData (byte[] data)
324 : this (new ASN1 (data))
328 public EnvelopedData (ASN1 asn1) : this ()
330 if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 3))
331 throw new ArgumentException ("Invalid EnvelopedData");
333 if (asn1[0][0].Tag != 0x02)
334 throw new ArgumentException ("Invalid version");
335 _version = asn1[0][0].Value[0];
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));
347 ASN1 encryptedContentInfo = asn1[0][2];
348 if (encryptedContentInfo.Tag != 0x30)
349 throw new ArgumentException ("missing EncryptedContentInfo");
351 ASN1 contentType = encryptedContentInfo [0];
352 if (contentType.Tag != 0x06)
353 throw new ArgumentException ("missing EncryptedContentInfo.ContentType");
354 _content = new ContentInfo (ASN1Convert.ToOid (contentType));
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];
362 ASN1 encryptedContent = encryptedContentInfo [2];
363 if (encryptedContent.Tag != 0x80)
364 throw new ArgumentException ("missing EncryptedContentInfo.EncryptedContent");
365 _encrypted = encryptedContent.Value;
368 public ArrayList RecipientInfos {
369 get { return _recipientInfos; }
373 get { return GetASN1(); }
376 public ContentInfo ContentInfo {
377 get { return _content; }
380 public ContentInfo EncryptionAlgorithm {
381 get { return _encryptionAlgorithm; }
384 public byte[] EncryptedContent {
386 if (_encrypted == null)
388 return (byte[]) _encrypted.Clone ();
392 public byte Version {
393 get { return _version; }
394 set { _version = value; }
397 internal ASN1 GetASN1 ()
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));
411 // contentInfo ContentInfo,
412 ASN1 ci = contentInfo.ASN1;
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);
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));
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));
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);*/
442 public byte[] GetBytes () {
443 return GetASN1 ().GetBytes ();
447 /* RecipientInfo ::= SEQUENCE {
449 * issuerAndSerialNumber IssuerAndSerialNumber,
450 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
451 * encryptedKey EncryptedKey
454 * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
456 * EncryptedKey ::= OCTET STRING
458 public class RecipientInfo {
460 private int _version;
464 private string _issuer;
465 private byte[] _serial;
467 public RecipientInfo () {}
469 public RecipientInfo (ASN1 data)
471 if (data.Tag != 0x30)
472 throw new ArgumentException ("Invalid RecipientInfo");
474 ASN1 version = data [0];
475 if (version.Tag != 0x02)
476 throw new ArgumentException ("missing Version");
477 _version = version.Value [0];
479 // issuerAndSerialNumber IssuerAndSerialNumber
480 ASN1 subjectIdentifierType = data [1];
481 if ((subjectIdentifierType.Tag == 0x80) && (_version == 3)) {
482 _ski = subjectIdentifierType.Value;
485 _issuer = X501.ToString (subjectIdentifierType [0]);
486 _serial = subjectIdentifierType [1].Value;
489 ASN1 keyEncryptionAlgorithm = data [2];
490 _oid = ASN1Convert.ToOid (keyEncryptionAlgorithm [0]);
492 ASN1 encryptedKey = data [3];
493 _key = encryptedKey.Value;
504 return (byte[]) _key.Clone ();
508 public byte[] SubjectKeyIdentifier {
512 return (byte[]) _ski.Clone ();
516 public string Issuer {
517 get { return _issuer; }
520 public byte[] Serial {
524 return (byte[]) _serial.Clone ();
529 get { return _version; }
534 * SignedData ::= SEQUENCE {
536 * digestAlgorithms DigestAlgorithmIdentifiers,
537 * contentInfo ContentInfo,
538 * certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
539 * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
540 * signerInfos SignerInfos
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;
556 contentInfo = new ContentInfo ();
557 certs = new X509CertificateCollection ();
558 crls = new ArrayList ();
559 signerInfo = new SignerInfo ();
564 public SignedData (byte[] data)
565 : this (new ASN1 (data))
569 public SignedData (ASN1 asn1)
571 if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 4))
572 throw new ArgumentException ("Invalid SignedData");
574 if (asn1[0][0].Tag != 0x02)
575 throw new ArgumentException ("Invalid version");
576 version = asn1[0][0].Value[0];
578 contentInfo = new ContentInfo (asn1[0][2]);
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 ()));
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 ());
595 if (asn1[0][n].Count > 0)
596 signerInfo = new SignerInfo (asn1[0][n]);
598 signerInfo = new SignerInfo ();
600 // Exchange hash algorithm Oid from SignerInfo
601 if (signerInfo.HashName != null) {
602 HashName = OidToName(signerInfo.HashName);
605 // Check if SignerInfo has authenticated attributes
606 mda = (signerInfo.AuthenticatedAttributes.Count > 0);
610 get { return GetASN1(); }
613 public X509CertificateCollection Certificates {
614 get { return certs; }
617 public ContentInfo ContentInfo {
618 get { return contentInfo; }
621 public ArrayList Crls {
625 public string HashName {
626 get { return hashAlgorithm; }
627 // todo add validation
629 hashAlgorithm = value;
630 signerInfo.HashName = value;
634 public SignerInfo SignerInfo {
635 get { return signerInfo; }
638 public byte Version {
639 get { return version; }
640 set { version = value; }
643 public bool UseAuthenticatedAttributes {
648 public bool VerifySignature (AsymmetricAlgorithm aa)
654 RSAPKCS1SignatureDeformatter r = new RSAPKCS1SignatureDeformatter (aa);
655 r.SetHashAlgorithm (hashAlgorithm);
656 HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
658 byte[] signature = signerInfo.Signature;
662 ASN1 asn = new ASN1 (0x31);
663 foreach (ASN1 attr in signerInfo.AuthenticatedAttributes)
666 hash = ha.ComputeHash (asn.GetBytes ());
668 hash = ha.ComputeHash (contentInfo.Content[0].Value);
671 if (hash != null && signature != null) {
672 return r.VerifySignature (hash, signature);
677 internal string OidToName (string oid)
680 case "1.3.14.3.2.26" :
682 case "1.2.840.113549.2.2" :
684 case "1.2.840.113549.2.5" :
686 case "2.16.840.1.101.3.4.1" :
688 case "2.16.840.1.101.3.4.2" :
690 case "2.16.840.1.101.3.4.3" :
699 internal ASN1 GetASN1 ()
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));
713 // contentInfo ContentInfo,
714 ASN1 ci = contentInfo.ASN1;
716 if (!signed && (hashAlgorithm != null)) {
718 // Use authenticated attributes for signature
720 // Automatically add the contentType authenticated attribute
721 ASN1 ctattr = Attribute (Oid.contentType, ci[0]);
722 signerInfo.AuthenticatedAttributes.Add (ctattr);
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);
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);
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));
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));
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);
760 public byte[] GetBytes ()
762 return GetASN1 ().GetBytes ();
767 * SignerInfo ::= SEQUENCE {
769 * issuerAndSerialNumber IssuerAndSerialNumber,
770 * digestAlgorithm DigestAlgorithmIdentifier,
771 * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
772 * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
773 * encryptedDigest EncryptedDigest,
774 * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
777 * For version == 3 issuerAndSerialNumber may be replaced by ...
779 public class SignerInfo {
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;
795 authenticatedAttributes = new ArrayList ();
796 unauthenticatedAttributes = new ArrayList ();
799 public SignerInfo (byte[] data)
800 : this (new ASN1 (data)) {}
803 public SignerInfo (ASN1 asn1) : this ()
805 if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 5))
806 throw new ArgumentException ("Invalid SignedData");
809 if (asn1[0][0].Tag != 0x02)
810 throw new ArgumentException ("Invalid version");
811 version = asn1[0][0].Value[0];
813 // issuerAndSerialNumber IssuerAndSerialNumber
814 ASN1 subjectIdentifierType = asn1 [0][1];
815 if ((subjectIdentifierType.Tag == 0x80) && (version == 3)) {
816 ski = subjectIdentifierType.Value;
819 issuer = X501.ToString (subjectIdentifierType [0]);
820 serial = subjectIdentifierType [1].Value;
823 // digestAlgorithm DigestAlgorithmIdentifier
824 ASN1 digestAlgorithm = asn1 [0][2];
825 hashAlgorithm = ASN1Convert.ToOid (digestAlgorithm [0]);
827 // authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL
829 ASN1 authAttributes = asn1 [0][n];
830 if (authAttributes.Tag == 0xA0) {
832 for (int i=0; i < authAttributes.Count; i++)
833 authenticatedAttributes.Add (authAttributes [i]);
836 // digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier
838 // ASN1 digestEncryptionAlgorithm = asn1 [0][n++];
839 // string digestEncryptionAlgorithmOid = ASN1Convert.ToOid (digestEncryptionAlgorithm [0]);
841 // encryptedDigest EncryptedDigest
842 ASN1 encryptedDigest = asn1 [0][n++];
843 if (encryptedDigest.Tag == 0x04)
844 signature = encryptedDigest.Value;
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]);
854 public string IssuerName {
855 get { return issuer; }
858 public byte[] SerialNumber {
862 return (byte[]) serial.Clone ();
866 public byte[] SubjectKeyIdentifier {
870 return (byte[]) ski.Clone ();
875 get { return GetASN1(); }
878 public ArrayList AuthenticatedAttributes {
879 get { return authenticatedAttributes; }
882 public X509Certificate Certificate {
884 set { x509 = value; }
887 public string HashName {
888 get { return hashAlgorithm; }
889 set { hashAlgorithm = value; }
892 public AsymmetricAlgorithm Key {
897 public byte[] Signature {
899 if (signature == null)
901 return (byte[]) signature.Clone ();
906 signature = (byte[]) value.Clone ();
911 public ArrayList UnauthenticatedAttributes {
912 get { return unauthenticatedAttributes; }
915 public byte Version {
916 get { return version; }
917 set { version = value; }
920 internal ASN1 GetASN1 ()
922 if ((key == null) || (hashAlgorithm == 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,
935 if (authenticatedAttributes.Count > 0) {
936 aa = signerInfo.Add (new ASN1 (0xA0));
937 authenticatedAttributes.Sort(new SortedSet ());
938 foreach (ASN1 attr in authenticatedAttributes)
941 // digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
943 signerInfo.Add (AlgorithmIdentifier (PKCS7.Oid.rsaEncryption));
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);
956 else if (key is DSA) {
957 throw new NotImplementedException ("not yet");
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)
973 public byte[] GetBytes ()
975 return GetASN1 ().GetBytes ();
979 internal class SortedSet : IComparer {
981 public int Compare (object x, object y)
984 return (y == null) ? 0 : -1;
991 if ((xx == null) || (yy == null)) {
992 throw new ArgumentException (Locale.GetText ("Invalid objects."));
995 byte[] xb = xx.GetBytes ();
996 byte[] yb = yy.GetBytes ();
998 for (int i = 0; i < xb.Length; i++) {
1005 return (xb[i] < yb[i]) ? -1 : 1;
1008 // The arrays are equal up to the shortest of them.
1009 if (xb.Length > yb.Length)
1011 else if (xb.Length < yb.Length)