Home | History | Annotate | Download | only in cms
      1 package org.bouncycastle.asn1.cms;
      2 
      3 import java.util.Enumeration;
      4 
      5 import org.bouncycastle.asn1.ASN1EncodableVector;
      6 import org.bouncycastle.asn1.ASN1Integer;
      7 import org.bouncycastle.asn1.ASN1Object;
      8 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
      9 import org.bouncycastle.asn1.ASN1Primitive;
     10 import org.bouncycastle.asn1.ASN1Sequence;
     11 import org.bouncycastle.asn1.ASN1Set;
     12 import org.bouncycastle.asn1.ASN1TaggedObject;
     13 import org.bouncycastle.asn1.BERSequence;
     14 import org.bouncycastle.asn1.BERSet;
     15 import org.bouncycastle.asn1.BERTaggedObject;
     16 import org.bouncycastle.asn1.DERTaggedObject;
     17 
     18 /**
     19  * <a href="http://tools.ietf.org/html/rfc5652#section-5.1">RFC 5652</a>:
     20  * <p>
     21  * A signed data object containing multitude of {@link SignerInfo}s.
     22  * <pre>
     23  * SignedData ::= SEQUENCE {
     24  *     version CMSVersion,
     25  *     digestAlgorithms DigestAlgorithmIdentifiers,
     26  *     encapContentInfo EncapsulatedContentInfo,
     27  *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
     28  *     crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
     29  *     signerInfos SignerInfos
     30  *   }
     31  *
     32  * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
     33  *
     34  * SignerInfos ::= SET OF SignerInfo
     35  * </pre>
     36  * <p>
     37  * The version calculation uses following ruleset from RFC 5652 section 5.1:
     38  * <pre>
     39  * IF ((certificates is present) AND
     40  *    (any certificates with a type of other are present)) OR
     41  *    ((crls is present) AND
     42  *    (any crls with a type of other are present))
     43  * THEN version MUST be 5
     44  * ELSE
     45  *    IF (certificates is present) AND
     46  *       (any version 2 attribute certificates are present)
     47  *    THEN version MUST be 4
     48  *    ELSE
     49  *       IF ((certificates is present) AND
     50  *          (any version 1 attribute certificates are present)) OR
     51  *          (any SignerInfo structures are version 3) OR
     52  *          (encapContentInfo eContentType is other than id-data)
     53  *       THEN version MUST be 3
     54  *       ELSE version MUST be 1
     55  * </pre>
     56  * <p>
     57  */
     58 public class SignedData
     59     extends ASN1Object
     60 {
     61     private static final ASN1Integer VERSION_1 = new ASN1Integer(1);
     62     private static final ASN1Integer VERSION_3 = new ASN1Integer(3);
     63     private static final ASN1Integer VERSION_4 = new ASN1Integer(4);
     64     private static final ASN1Integer VERSION_5 = new ASN1Integer(5);
     65 
     66     private ASN1Integer version;
     67     private ASN1Set     digestAlgorithms;
     68     private ContentInfo contentInfo;
     69     private ASN1Set     certificates;
     70     private ASN1Set     crls;
     71     private ASN1Set     signerInfos;
     72     private boolean certsBer;
     73     private boolean        crlsBer;
     74 
     75     /**
     76      * Return a SignedData object from the given object.
     77      * <p>
     78      * Accepted inputs:
     79      * <ul>
     80      * <li> null &rarr; null
     81      * <li> {@link SignedData} object
     82      * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with SignedData structure inside
     83      * </ul>
     84      *
     85      * @param o the object we want converted.
     86      * @return a reference that can be assigned to SignedData (may be null)
     87      * @throws IllegalArgumentException if the object cannot be converted.
     88      */
     89     public static SignedData getInstance(
     90         Object  o)
     91     {
     92         if (o instanceof SignedData)
     93         {
     94             return (SignedData)o;
     95         }
     96         else if (o != null)
     97         {
     98             return new SignedData(ASN1Sequence.getInstance(o));
     99         }
    100 
    101         return null;
    102     }
    103 
    104     public SignedData(
    105         ASN1Set     digestAlgorithms,
    106         ContentInfo contentInfo,
    107         ASN1Set     certificates,
    108         ASN1Set     crls,
    109         ASN1Set     signerInfos)
    110     {
    111         this.version = calculateVersion(contentInfo.getContentType(), certificates, crls, signerInfos);
    112         this.digestAlgorithms = digestAlgorithms;
    113         this.contentInfo = contentInfo;
    114         this.certificates = certificates;
    115         this.crls = crls;
    116         this.signerInfos = signerInfos;
    117         this.crlsBer = crls instanceof BERSet;
    118         this.certsBer = certificates instanceof BERSet;
    119     }
    120 
    121 
    122     private ASN1Integer calculateVersion(
    123         ASN1ObjectIdentifier contentOid,
    124         ASN1Set certs,
    125         ASN1Set crls,
    126         ASN1Set signerInfs)
    127     {
    128         boolean otherCert = false;
    129         boolean otherCrl = false;
    130         boolean attrCertV1Found = false;
    131         boolean attrCertV2Found = false;
    132 
    133         if (certs != null)
    134         {
    135             for (Enumeration en = certs.getObjects(); en.hasMoreElements();)
    136             {
    137                 Object obj = en.nextElement();
    138                 if (obj instanceof ASN1TaggedObject)
    139                 {
    140                     ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(obj);
    141 
    142                     if (tagged.getTagNo() == 1)
    143                     {
    144                         attrCertV1Found = true;
    145                     }
    146                     else if (tagged.getTagNo() == 2)
    147                     {
    148                         attrCertV2Found = true;
    149                     }
    150                     else if (tagged.getTagNo() == 3)
    151                     {
    152                         otherCert = true;
    153                     }
    154                 }
    155             }
    156         }
    157 
    158         if (otherCert)
    159         {
    160             return new ASN1Integer(5);
    161         }
    162 
    163         if (crls != null)         // no need to check if otherCert is true
    164         {
    165             for (Enumeration en = crls.getObjects(); en.hasMoreElements();)
    166             {
    167                 Object obj = en.nextElement();
    168                 if (obj instanceof ASN1TaggedObject)
    169                 {
    170                     otherCrl = true;
    171                 }
    172             }
    173         }
    174 
    175         if (otherCrl)
    176         {
    177             return VERSION_5;
    178         }
    179 
    180         if (attrCertV2Found)
    181         {
    182             return VERSION_4;
    183         }
    184 
    185         if (attrCertV1Found)
    186         {
    187             return VERSION_3;
    188         }
    189 
    190         if (checkForVersion3(signerInfs))
    191         {
    192             return VERSION_3;
    193         }
    194 
    195         if (!CMSObjectIdentifiers.data.equals(contentOid))
    196         {
    197             return VERSION_3;
    198         }
    199 
    200         return VERSION_1;
    201     }
    202 
    203     private boolean checkForVersion3(ASN1Set signerInfs)
    204     {
    205         for (Enumeration e = signerInfs.getObjects(); e.hasMoreElements();)
    206         {
    207             SignerInfo s = SignerInfo.getInstance(e.nextElement());
    208 
    209             if (s.getVersion().getValue().intValue() == 3)
    210             {
    211                 return true;
    212             }
    213         }
    214 
    215         return false;
    216     }
    217 
    218     private SignedData(
    219         ASN1Sequence seq)
    220     {
    221         Enumeration     e = seq.getObjects();
    222 
    223         version = ASN1Integer.getInstance(e.nextElement());
    224         digestAlgorithms = ((ASN1Set)e.nextElement());
    225         contentInfo = ContentInfo.getInstance(e.nextElement());
    226 
    227         while (e.hasMoreElements())
    228         {
    229             ASN1Primitive o = (ASN1Primitive)e.nextElement();
    230 
    231             //
    232             // an interesting feature of SignedData is that there appear
    233             // to be varying implementations...
    234             // for the moment we ignore anything which doesn't fit.
    235             //
    236             if (o instanceof ASN1TaggedObject)
    237             {
    238                 ASN1TaggedObject tagged = (ASN1TaggedObject)o;
    239 
    240                 switch (tagged.getTagNo())
    241                 {
    242                 case 0:
    243                     certsBer = tagged instanceof BERTaggedObject;
    244                     certificates = ASN1Set.getInstance(tagged, false);
    245                     break;
    246                 case 1:
    247                     crlsBer = tagged instanceof BERTaggedObject;
    248                     crls = ASN1Set.getInstance(tagged, false);
    249                     break;
    250                 default:
    251                     throw new IllegalArgumentException("unknown tag value " + tagged.getTagNo());
    252                 }
    253             }
    254             else
    255             {
    256                 signerInfos = (ASN1Set)o;
    257             }
    258         }
    259     }
    260 
    261     public ASN1Integer getVersion()
    262     {
    263         return version;
    264     }
    265 
    266     public ASN1Set getDigestAlgorithms()
    267     {
    268         return digestAlgorithms;
    269     }
    270 
    271     public ContentInfo getEncapContentInfo()
    272     {
    273         return contentInfo;
    274     }
    275 
    276     public ASN1Set getCertificates()
    277     {
    278         return certificates;
    279     }
    280 
    281     public ASN1Set getCRLs()
    282     {
    283         return crls;
    284     }
    285 
    286     public ASN1Set getSignerInfos()
    287     {
    288         return signerInfos;
    289     }
    290 
    291     /**
    292      * Produce an object suitable for an ASN1OutputStream.
    293      */
    294     public ASN1Primitive toASN1Primitive()
    295     {
    296         ASN1EncodableVector  v = new ASN1EncodableVector();
    297 
    298         v.add(version);
    299         v.add(digestAlgorithms);
    300         v.add(contentInfo);
    301 
    302         if (certificates != null)
    303         {
    304             if (certsBer)
    305             {
    306                 v.add(new BERTaggedObject(false, 0, certificates));
    307             }
    308             else
    309             {
    310                 v.add(new DERTaggedObject(false, 0, certificates));
    311             }
    312         }
    313 
    314         if (crls != null)
    315         {
    316             if (crlsBer)
    317             {
    318                 v.add(new BERTaggedObject(false, 1, crls));
    319             }
    320             else
    321             {
    322                 v.add(new DERTaggedObject(false, 1, crls));
    323             }
    324         }
    325 
    326         v.add(signerInfos);
    327 
    328         return new BERSequence(v);
    329     }
    330 }
    331