1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012 |
- //
- // PKCS7.cs: PKCS #7 - Cryptographic Message Syntax Standard
- // http://www.rsasecurity.com/rsalabs/pkcs/pkcs-7/index.html
- //
- // Authors:
- // Sebastien Pouliot <sebastien@ximian.com>
- // Daniel Granath <dgranath#gmail.com>
- //
- // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
- // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- using System;
- using System.Collections;
- using System.Security.Cryptography;
- namespace Emby.Server.Core.Cryptography
- {
- public sealed class PKCS7 {
- public class Oid {
- // pkcs 1
- public const string rsaEncryption = "1.2.840.113549.1.1.1";
- // pkcs 7
- public const string data = "1.2.840.113549.1.7.1";
- public const string signedData = "1.2.840.113549.1.7.2";
- public const string envelopedData = "1.2.840.113549.1.7.3";
- public const string signedAndEnvelopedData = "1.2.840.113549.1.7.4";
- public const string digestedData = "1.2.840.113549.1.7.5";
- public const string encryptedData = "1.2.840.113549.1.7.6";
- // pkcs 9
- public const string contentType = "1.2.840.113549.1.9.3";
- public const string messageDigest = "1.2.840.113549.1.9.4";
- public const string signingTime = "1.2.840.113549.1.9.5";
- public const string countersignature = "1.2.840.113549.1.9.6";
- public Oid ()
- {
- }
- }
- private PKCS7 ()
- {
- }
- static public ASN1 Attribute (string oid, ASN1 value)
- {
- ASN1 attr = new ASN1 (0x30);
- attr.Add (ASN1Convert.FromOid (oid));
- ASN1 aset = attr.Add (new ASN1 (0x31));
- aset.Add (value);
- return attr;
- }
- static public ASN1 AlgorithmIdentifier (string oid)
- {
- ASN1 ai = new ASN1 (0x30);
- ai.Add (ASN1Convert.FromOid (oid));
- ai.Add (new ASN1 (0x05)); // NULL
- return ai;
- }
- static public ASN1 AlgorithmIdentifier (string oid, ASN1 parameters)
- {
- ASN1 ai = new ASN1 (0x30);
- ai.Add (ASN1Convert.FromOid (oid));
- ai.Add (parameters);
- return ai;
- }
- /*
- * IssuerAndSerialNumber ::= SEQUENCE {
- * issuer Name,
- * serialNumber CertificateSerialNumber
- * }
- */
- static public ASN1 IssuerAndSerialNumber (X509Certificate x509)
- {
- ASN1 issuer = null;
- ASN1 serial = null;
- ASN1 cert = new ASN1 (x509.RawData);
- int tbs = 0;
- bool flag = false;
- while (tbs < cert[0].Count) {
- ASN1 e = cert[0][tbs++];
- if (e.Tag == 0x02)
- serial = e;
- else if (e.Tag == 0x30) {
- if (flag) {
- issuer = e;
- break;
- }
- flag = true;
- }
- }
- ASN1 iasn = new ASN1 (0x30);
- iasn.Add (issuer);
- iasn.Add (serial);
- return iasn;
- }
- /*
- * ContentInfo ::= SEQUENCE {
- * contentType ContentType,
- * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
- * }
- * ContentType ::= OBJECT IDENTIFIER
- */
- public class ContentInfo {
- private string contentType;
- private ASN1 content;
- public ContentInfo ()
- {
- content = new ASN1 (0xA0);
- }
- public ContentInfo (string oid) : this ()
- {
- contentType = oid;
- }
- public ContentInfo (byte[] data)
- : this (new ASN1 (data)) {}
- public ContentInfo (ASN1 asn1)
- {
- // SEQUENCE with 1 or 2 elements
- if ((asn1.Tag != 0x30) || ((asn1.Count < 1) && (asn1.Count > 2)))
- throw new ArgumentException ("Invalid ASN1");
- if (asn1[0].Tag != 0x06)
- throw new ArgumentException ("Invalid contentType");
- contentType = ASN1Convert.ToOid (asn1[0]);
- if (asn1.Count > 1) {
- if (asn1[1].Tag != 0xA0)
- throw new ArgumentException ("Invalid content");
- content = asn1[1];
- }
- }
- public ASN1 ASN1 {
- get { return GetASN1(); }
- }
- public ASN1 Content {
- get { return content; }
- set { content = value; }
- }
- public string ContentType {
- get { return contentType; }
- set { contentType = value; }
- }
- internal ASN1 GetASN1 ()
- {
- // ContentInfo ::= SEQUENCE {
- ASN1 contentInfo = new ASN1 (0x30);
- // contentType ContentType, -> ContentType ::= OBJECT IDENTIFIER
- contentInfo.Add (ASN1Convert.FromOid (contentType));
- // content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
- if ((content != null) && (content.Count > 0))
- contentInfo.Add (content);
- return contentInfo;
- }
- public byte[] GetBytes ()
- {
- return GetASN1 ().GetBytes ();
- }
- }
- /*
- * EncryptedData ::= SEQUENCE {
- * version INTEGER {edVer0(0)} (edVer0),
- * encryptedContentInfo EncryptedContentInfo
- * }
- */
- public class EncryptedData {
- private byte _version;
- private ContentInfo _content;
- private ContentInfo _encryptionAlgorithm;
- private byte[] _encrypted;
- public EncryptedData ()
- {
- _version = 0;
- }
- public EncryptedData (byte[] data)
- : this (new ASN1 (data))
- {
- }
- public EncryptedData (ASN1 asn1) : this ()
- {
- if ((asn1.Tag != 0x30) || (asn1.Count < 2))
- throw new ArgumentException ("Invalid EncryptedData");
- if (asn1 [0].Tag != 0x02)
- throw new ArgumentException ("Invalid version");
- _version = asn1 [0].Value [0];
- ASN1 encryptedContentInfo = asn1 [1];
- if (encryptedContentInfo.Tag != 0x30)
- throw new ArgumentException ("missing EncryptedContentInfo");
- ASN1 contentType = encryptedContentInfo [0];
- if (contentType.Tag != 0x06)
- throw new ArgumentException ("missing EncryptedContentInfo.ContentType");
- _content = new ContentInfo (ASN1Convert.ToOid (contentType));
- ASN1 contentEncryptionAlgorithm = encryptedContentInfo [1];
- if (contentEncryptionAlgorithm.Tag != 0x30)
- throw new ArgumentException ("missing EncryptedContentInfo.ContentEncryptionAlgorithmIdentifier");
- _encryptionAlgorithm = new ContentInfo (ASN1Convert.ToOid (contentEncryptionAlgorithm [0]));
- _encryptionAlgorithm.Content = contentEncryptionAlgorithm [1];
-
- ASN1 encryptedContent = encryptedContentInfo [2];
- if (encryptedContent.Tag != 0x80)
- throw new ArgumentException ("missing EncryptedContentInfo.EncryptedContent");
- _encrypted = encryptedContent.Value;
- }
- public ASN1 ASN1 {
- get { return GetASN1(); }
- }
- public ContentInfo ContentInfo {
- get { return _content; }
- }
- public ContentInfo EncryptionAlgorithm {
- get { return _encryptionAlgorithm; }
- }
- public byte[] EncryptedContent {
- get {
- if (_encrypted == null)
- return null;
- return (byte[]) _encrypted.Clone ();
- }
- }
- public byte Version {
- get { return _version; }
- set { _version = value; }
- }
- // methods
- internal ASN1 GetASN1 ()
- {
- return null;
- }
- public byte[] GetBytes ()
- {
- return GetASN1 ().GetBytes ();
- }
- }
- /*
- * EnvelopedData ::= SEQUENCE {
- * version Version,
- * recipientInfos RecipientInfos,
- * encryptedContentInfo EncryptedContentInfo
- * }
- *
- * RecipientInfos ::= SET OF RecipientInfo
- *
- * EncryptedContentInfo ::= SEQUENCE {
- * contentType ContentType,
- * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
- * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
- * }
- *
- * EncryptedContent ::= OCTET STRING
- *
- */
- public class EnvelopedData {
- private byte _version;
- private ContentInfo _content;
- private ContentInfo _encryptionAlgorithm;
- private ArrayList _recipientInfos;
- private byte[] _encrypted;
- public EnvelopedData ()
- {
- _version = 0;
- _content = new ContentInfo ();
- _encryptionAlgorithm = new ContentInfo ();
- _recipientInfos = new ArrayList ();
- }
- public EnvelopedData (byte[] data)
- : this (new ASN1 (data))
- {
- }
- public EnvelopedData (ASN1 asn1) : this ()
- {
- if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 3))
- throw new ArgumentException ("Invalid EnvelopedData");
- if (asn1[0][0].Tag != 0x02)
- throw new ArgumentException ("Invalid version");
- _version = asn1[0][0].Value[0];
- // recipientInfos
- ASN1 recipientInfos = asn1 [0][1];
- if (recipientInfos.Tag != 0x31)
- throw new ArgumentException ("missing RecipientInfos");
- for (int i=0; i < recipientInfos.Count; i++) {
- ASN1 recipientInfo = recipientInfos [i];
- _recipientInfos.Add (new RecipientInfo (recipientInfo));
- }
- ASN1 encryptedContentInfo = asn1[0][2];
- if (encryptedContentInfo.Tag != 0x30)
- throw new ArgumentException ("missing EncryptedContentInfo");
- ASN1 contentType = encryptedContentInfo [0];
- if (contentType.Tag != 0x06)
- throw new ArgumentException ("missing EncryptedContentInfo.ContentType");
- _content = new ContentInfo (ASN1Convert.ToOid (contentType));
- ASN1 contentEncryptionAlgorithm = encryptedContentInfo [1];
- if (contentEncryptionAlgorithm.Tag != 0x30)
- throw new ArgumentException ("missing EncryptedContentInfo.ContentEncryptionAlgorithmIdentifier");
- _encryptionAlgorithm = new ContentInfo (ASN1Convert.ToOid (contentEncryptionAlgorithm [0]));
- _encryptionAlgorithm.Content = contentEncryptionAlgorithm [1];
-
- ASN1 encryptedContent = encryptedContentInfo [2];
- if (encryptedContent.Tag != 0x80)
- throw new ArgumentException ("missing EncryptedContentInfo.EncryptedContent");
- _encrypted = encryptedContent.Value;
- }
- public ArrayList RecipientInfos {
- get { return _recipientInfos; }
- }
- public ASN1 ASN1 {
- get { return GetASN1(); }
- }
- public ContentInfo ContentInfo {
- get { return _content; }
- }
- public ContentInfo EncryptionAlgorithm {
- get { return _encryptionAlgorithm; }
- }
- public byte[] EncryptedContent {
- get {
- if (_encrypted == null)
- return null;
- return (byte[]) _encrypted.Clone ();
- }
- }
- public byte Version {
- get { return _version; }
- set { _version = value; }
- }
- internal ASN1 GetASN1 ()
- {
- // SignedData ::= SEQUENCE {
- ASN1 signedData = new ASN1 (0x30);
- // version Version -> Version ::= INTEGER
- /* byte[] ver = { _version };
- signedData.Add (new ASN1 (0x02, ver));
- // digestAlgorithms DigestAlgorithmIdentifiers -> DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
- ASN1 digestAlgorithms = signedData.Add (new ASN1 (0x31));
- if (hashAlgorithm != null) {
- string hashOid = CryptoConfig.MapNameToOid (hashAlgorithm);
- digestAlgorithms.Add (AlgorithmIdentifier (hashOid));
- }
- // contentInfo ContentInfo,
- ASN1 ci = contentInfo.ASN1;
- signedData.Add (ci);
- if ((mda == null) && (hashAlgorithm != null)) {
- // automatically add the messageDigest authenticated attribute
- HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
- byte[] idcHash = ha.ComputeHash (ci[1][0].Value);
- ASN1 md = new ASN1 (0x30);
- mda = Attribute (messageDigest, md.Add (new ASN1 (0x04, idcHash)));
- signerInfo.AuthenticatedAttributes.Add (mda);
- }
- // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
- if (certs.Count > 0) {
- ASN1 a0 = signedData.Add (new ASN1 (0xA0));
- foreach (X509Certificate x in certs)
- a0.Add (new ASN1 (x.RawData));
- }
- // crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
- if (crls.Count > 0) {
- ASN1 a1 = signedData.Add (new ASN1 (0xA1));
- foreach (byte[] crl in crls)
- a1.Add (new ASN1 (crl));
- }
- // signerInfos SignerInfos -> SignerInfos ::= SET OF SignerInfo
- ASN1 signerInfos = signedData.Add (new ASN1 (0x31));
- if (signerInfo.Key != null)
- signerInfos.Add (signerInfo.ASN1);*/
- return signedData;
- }
- public byte[] GetBytes () {
- return GetASN1 ().GetBytes ();
- }
- }
- /* RecipientInfo ::= SEQUENCE {
- * version Version,
- * issuerAndSerialNumber IssuerAndSerialNumber,
- * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
- * encryptedKey EncryptedKey
- * }
- *
- * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
- *
- * EncryptedKey ::= OCTET STRING
- */
- public class RecipientInfo {
- private int _version;
- private string _oid;
- private byte[] _key;
- private byte[] _ski;
- private string _issuer;
- private byte[] _serial;
- public RecipientInfo () {}
- public RecipientInfo (ASN1 data)
- {
- if (data.Tag != 0x30)
- throw new ArgumentException ("Invalid RecipientInfo");
-
- ASN1 version = data [0];
- if (version.Tag != 0x02)
- throw new ArgumentException ("missing Version");
- _version = version.Value [0];
- // issuerAndSerialNumber IssuerAndSerialNumber
- ASN1 subjectIdentifierType = data [1];
- if ((subjectIdentifierType.Tag == 0x80) && (_version == 3)) {
- _ski = subjectIdentifierType.Value;
- }
- else {
- _issuer = X501.ToString (subjectIdentifierType [0]);
- _serial = subjectIdentifierType [1].Value;
- }
- ASN1 keyEncryptionAlgorithm = data [2];
- _oid = ASN1Convert.ToOid (keyEncryptionAlgorithm [0]);
- ASN1 encryptedKey = data [3];
- _key = encryptedKey.Value;
- }
- public string Oid {
- get { return _oid; }
- }
- public byte[] Key {
- get {
- if (_key == null)
- return null;
- return (byte[]) _key.Clone ();
- }
- }
- public byte[] SubjectKeyIdentifier {
- get {
- if (_ski == null)
- return null;
- return (byte[]) _ski.Clone ();
- }
- }
- public string Issuer {
- get { return _issuer; }
- }
- public byte[] Serial {
- get {
- if (_serial == null)
- return null;
- return (byte[]) _serial.Clone ();
- }
- }
- public int Version {
- get { return _version; }
- }
- }
- /*
- * SignedData ::= SEQUENCE {
- * version Version,
- * digestAlgorithms DigestAlgorithmIdentifiers,
- * contentInfo ContentInfo,
- * certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
- * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
- * signerInfos SignerInfos
- * }
- */
- public class SignedData {
- private byte version;
- private string hashAlgorithm;
- private ContentInfo contentInfo;
- private X509CertificateCollection certs;
- private ArrayList crls;
- private SignerInfo signerInfo;
- private bool mda;
- private bool signed;
- public SignedData ()
- {
- version = 1;
- contentInfo = new ContentInfo ();
- certs = new X509CertificateCollection ();
- crls = new ArrayList ();
- signerInfo = new SignerInfo ();
- mda = true;
- signed = false;
- }
- public SignedData (byte[] data)
- : this (new ASN1 (data))
- {
- }
- public SignedData (ASN1 asn1)
- {
- if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 4))
- throw new ArgumentException ("Invalid SignedData");
- if (asn1[0][0].Tag != 0x02)
- throw new ArgumentException ("Invalid version");
- version = asn1[0][0].Value[0];
- contentInfo = new ContentInfo (asn1[0][2]);
- int n = 3;
- certs = new X509CertificateCollection ();
- if (asn1[0][n].Tag == 0xA0) {
- for (int i=0; i < asn1[0][n].Count; i++)
- certs.Add (new X509Certificate (asn1[0][n][i].GetBytes ()));
- n++;
- }
- crls = new ArrayList ();
- if (asn1[0][n].Tag == 0xA1) {
- for (int i=0; i < asn1[0][n].Count; i++)
- crls.Add (asn1[0][n][i].GetBytes ());
- n++;
- }
- if (asn1[0][n].Count > 0)
- signerInfo = new SignerInfo (asn1[0][n]);
- else
- signerInfo = new SignerInfo ();
- // Exchange hash algorithm Oid from SignerInfo
- if (signerInfo.HashName != null) {
- HashName = OidToName(signerInfo.HashName);
- }
-
- // Check if SignerInfo has authenticated attributes
- mda = (signerInfo.AuthenticatedAttributes.Count > 0);
- }
- public ASN1 ASN1 {
- get { return GetASN1(); }
- }
- public X509CertificateCollection Certificates {
- get { return certs; }
- }
- public ContentInfo ContentInfo {
- get { return contentInfo; }
- }
- public ArrayList Crls {
- get { return crls; }
- }
- public string HashName {
- get { return hashAlgorithm; }
- // todo add validation
- set {
- hashAlgorithm = value;
- signerInfo.HashName = value;
- }
- }
- public SignerInfo SignerInfo {
- get { return signerInfo; }
- }
- public byte Version {
- get { return version; }
- set { version = value; }
- }
- public bool UseAuthenticatedAttributes {
- get { return mda; }
- set { mda = value; }
- }
- public bool VerifySignature (AsymmetricAlgorithm aa)
- {
- if (aa == null) {
- return false;
- }
- RSAPKCS1SignatureDeformatter r = new RSAPKCS1SignatureDeformatter (aa);
- r.SetHashAlgorithm (hashAlgorithm);
- HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
- byte[] signature = signerInfo.Signature;
- byte[] hash = null;
- if (mda) {
- ASN1 asn = new ASN1 (0x31);
- foreach (ASN1 attr in signerInfo.AuthenticatedAttributes)
- asn.Add (attr);
- hash = ha.ComputeHash (asn.GetBytes ());
- } else {
- hash = ha.ComputeHash (contentInfo.Content[0].Value);
- }
- if (hash != null && signature != null) {
- return r.VerifySignature (hash, signature);
- }
- return false;
- }
- internal string OidToName (string oid)
- {
- switch (oid) {
- case "1.3.14.3.2.26" :
- return "SHA1";
- case "1.2.840.113549.2.2" :
- return "MD2";
- case "1.2.840.113549.2.5" :
- return "MD5";
- case "2.16.840.1.101.3.4.1" :
- return "SHA256";
- case "2.16.840.1.101.3.4.2" :
- return "SHA384";
- case "2.16.840.1.101.3.4.3" :
- return "SHA512";
- default :
- break;
- }
- // Unknown Oid
- return oid;
- }
- internal ASN1 GetASN1 ()
- {
- // SignedData ::= SEQUENCE {
- ASN1 signedData = new ASN1 (0x30);
- // version Version -> Version ::= INTEGER
- byte[] ver = { version };
- signedData.Add (new ASN1 (0x02, ver));
- // digestAlgorithms DigestAlgorithmIdentifiers -> DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
- ASN1 digestAlgorithms = signedData.Add (new ASN1 (0x31));
- if (hashAlgorithm != null) {
- string hashOid = CryptoConfig.MapNameToOID (hashAlgorithm);
- digestAlgorithms.Add (AlgorithmIdentifier (hashOid));
- }
- // contentInfo ContentInfo,
- ASN1 ci = contentInfo.ASN1;
- signedData.Add (ci);
- if (!signed && (hashAlgorithm != null)) {
- if (mda) {
- // Use authenticated attributes for signature
-
- // Automatically add the contentType authenticated attribute
- ASN1 ctattr = Attribute (Oid.contentType, ci[0]);
- signerInfo.AuthenticatedAttributes.Add (ctattr);
-
- // Automatically add the messageDigest authenticated attribute
- HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
- byte[] idcHash = ha.ComputeHash (ci[1][0].Value);
- ASN1 md = new ASN1 (0x30);
- ASN1 mdattr = Attribute (Oid.messageDigest, md.Add (new ASN1 (0x04, idcHash)));
- signerInfo.AuthenticatedAttributes.Add (mdattr);
- } else {
- // Don't use authenticated attributes for signature -- signature is content
- RSAPKCS1SignatureFormatter r = new RSAPKCS1SignatureFormatter (signerInfo.Key);
- r.SetHashAlgorithm (hashAlgorithm);
- HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
- byte[] sig = ha.ComputeHash (ci[1][0].Value);
- signerInfo.Signature = r.CreateSignature (sig);
- }
- signed = true;
- }
- // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
- if (certs.Count > 0) {
- ASN1 a0 = signedData.Add (new ASN1 (0xA0));
- foreach (X509Certificate x in certs)
- a0.Add (new ASN1 (x.RawData));
- }
- // crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
- if (crls.Count > 0) {
- ASN1 a1 = signedData.Add (new ASN1 (0xA1));
- foreach (byte[] crl in crls)
- a1.Add (new ASN1 (crl));
- }
- // signerInfos SignerInfos -> SignerInfos ::= SET OF SignerInfo
- ASN1 signerInfos = signedData.Add (new ASN1 (0x31));
- if (signerInfo.Key != null)
- signerInfos.Add (signerInfo.ASN1);
- return signedData;
- }
- public byte[] GetBytes ()
- {
- return GetASN1 ().GetBytes ();
- }
- }
- /*
- * SignerInfo ::= SEQUENCE {
- * version Version,
- * issuerAndSerialNumber IssuerAndSerialNumber,
- * digestAlgorithm DigestAlgorithmIdentifier,
- * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
- * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
- * encryptedDigest EncryptedDigest,
- * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
- * }
- *
- * For version == 3 issuerAndSerialNumber may be replaced by ...
- */
- public class SignerInfo {
- private byte version;
- private X509Certificate x509;
- private string hashAlgorithm;
- private AsymmetricAlgorithm key;
- private ArrayList authenticatedAttributes;
- private ArrayList unauthenticatedAttributes;
- private byte[] signature;
- private string issuer;
- private byte[] serial;
- private byte[] ski;
- public SignerInfo ()
- {
- version = 1;
- authenticatedAttributes = new ArrayList ();
- unauthenticatedAttributes = new ArrayList ();
- }
- public SignerInfo (byte[] data)
- : this (new ASN1 (data)) {}
- // TODO: INCOMPLETE
- public SignerInfo (ASN1 asn1) : this ()
- {
- if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 5))
- throw new ArgumentException ("Invalid SignedData");
- // version Version
- if (asn1[0][0].Tag != 0x02)
- throw new ArgumentException ("Invalid version");
- version = asn1[0][0].Value[0];
- // issuerAndSerialNumber IssuerAndSerialNumber
- ASN1 subjectIdentifierType = asn1 [0][1];
- if ((subjectIdentifierType.Tag == 0x80) && (version == 3)) {
- ski = subjectIdentifierType.Value;
- }
- else {
- issuer = X501.ToString (subjectIdentifierType [0]);
- serial = subjectIdentifierType [1].Value;
- }
- // digestAlgorithm DigestAlgorithmIdentifier
- ASN1 digestAlgorithm = asn1 [0][2];
- hashAlgorithm = ASN1Convert.ToOid (digestAlgorithm [0]);
- // authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL
- int n = 3;
- ASN1 authAttributes = asn1 [0][n];
- if (authAttributes.Tag == 0xA0) {
- n++;
- for (int i=0; i < authAttributes.Count; i++)
- authenticatedAttributes.Add (authAttributes [i]);
- }
- // digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier
- n++;
- // ASN1 digestEncryptionAlgorithm = asn1 [0][n++];
- // string digestEncryptionAlgorithmOid = ASN1Convert.ToOid (digestEncryptionAlgorithm [0]);
- // encryptedDigest EncryptedDigest
- ASN1 encryptedDigest = asn1 [0][n++];
- if (encryptedDigest.Tag == 0x04)
- signature = encryptedDigest.Value;
- // unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
- ASN1 unauthAttributes = asn1 [0][n];
- if ((unauthAttributes != null) && (unauthAttributes.Tag == 0xA1)) {
- for (int i=0; i < unauthAttributes.Count; i++)
- unauthenticatedAttributes.Add (unauthAttributes [i]);
- }
- }
- public string IssuerName {
- get { return issuer; }
- }
- public byte[] SerialNumber {
- get {
- if (serial == null)
- return null;
- return (byte[]) serial.Clone ();
- }
- }
- public byte[] SubjectKeyIdentifier {
- get {
- if (ski == null)
- return null;
- return (byte[]) ski.Clone ();
- }
- }
- public ASN1 ASN1 {
- get { return GetASN1(); }
- }
- public ArrayList AuthenticatedAttributes {
- get { return authenticatedAttributes; }
- }
- public X509Certificate Certificate {
- get { return x509; }
- set { x509 = value; }
- }
- public string HashName {
- get { return hashAlgorithm; }
- set { hashAlgorithm = value; }
- }
- public AsymmetricAlgorithm Key {
- get { return key; }
- set { key = value; }
- }
- public byte[] Signature {
- get {
- if (signature == null)
- return null;
- return (byte[]) signature.Clone ();
- }
- set {
- if (value != null) {
- signature = (byte[]) value.Clone ();
- }
- }
- }
- public ArrayList UnauthenticatedAttributes {
- get { return unauthenticatedAttributes; }
- }
- public byte Version {
- get { return version; }
- set { version = value; }
- }
- internal ASN1 GetASN1 ()
- {
- if ((key == null) || (hashAlgorithm == null))
- return null;
- byte[] ver = { version };
- ASN1 signerInfo = new ASN1 (0x30);
- // version Version -> Version ::= INTEGER
- signerInfo.Add (new ASN1 (0x02, ver));
- // issuerAndSerialNumber IssuerAndSerialNumber,
- signerInfo.Add (PKCS7.IssuerAndSerialNumber (x509));
- // digestAlgorithm DigestAlgorithmIdentifier,
- string hashOid = CryptoConfig.MapNameToOID (hashAlgorithm);
- signerInfo.Add (AlgorithmIdentifier (hashOid));
- // authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
- ASN1 aa = null;
- if (authenticatedAttributes.Count > 0) {
- aa = signerInfo.Add (new ASN1 (0xA0));
- authenticatedAttributes.Sort(new SortedSet ());
- foreach (ASN1 attr in authenticatedAttributes)
- aa.Add (attr);
- }
- // digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
- if (key is RSA) {
- signerInfo.Add (AlgorithmIdentifier (PKCS7.Oid.rsaEncryption));
- if (aa != null) {
- // Calculate the signature here; otherwise it must be set from SignedData
- RSAPKCS1SignatureFormatter r = new RSAPKCS1SignatureFormatter (key);
- r.SetHashAlgorithm (hashAlgorithm);
- byte[] tbs = aa.GetBytes ();
- tbs [0] = 0x31; // not 0xA0 for signature
- HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm);
- byte[] tbsHash = ha.ComputeHash (tbs);
- signature = r.CreateSignature (tbsHash);
- }
- }
- else if (key is DSA) {
- throw new NotImplementedException ("not yet");
- }
- else
- throw new CryptographicException ("Unknown assymetric algorithm");
- // encryptedDigest EncryptedDigest,
- signerInfo.Add (new ASN1 (0x04, signature));
- // unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
- if (unauthenticatedAttributes.Count > 0) {
- ASN1 ua = signerInfo.Add (new ASN1 (0xA1));
- unauthenticatedAttributes.Sort(new SortedSet ());
- foreach (ASN1 attr in unauthenticatedAttributes)
- ua.Add (attr);
- }
- return signerInfo;
- }
- public byte[] GetBytes ()
- {
- return GetASN1 ().GetBytes ();
- }
- }
- internal class SortedSet : IComparer {
- public int Compare (object x, object y)
- {
- if (x == null)
- return (y == null) ? 0 : -1;
- else if (y == null)
- return 1;
- ASN1 xx = x as ASN1;
- ASN1 yy = y as ASN1;
-
- if ((xx == null) || (yy == null)) {
- throw new ArgumentException (("Invalid objects."));
- }
- byte[] xb = xx.GetBytes ();
- byte[] yb = yy.GetBytes ();
- for (int i = 0; i < xb.Length; i++) {
- if (i == yb.Length)
- break;
- if (xb[i] == yb[i])
- continue;
-
- return (xb[i] < yb[i]) ? -1 : 1;
- }
- // The arrays are equal up to the shortest of them.
- if (xb.Length > yb.Length)
- return 1;
- else if (xb.Length < yb.Length)
- return -1;
- return 0;
- }
- }
- }
- }
|