1 package org.bouncycastle.cms; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 6 import org.bouncycastle.asn1.ASN1Encodable; 7 import org.bouncycastle.asn1.ASN1EncodableVector; 8 import org.bouncycastle.asn1.ASN1OctetString; 9 import org.bouncycastle.asn1.ASN1Set; 10 import org.bouncycastle.asn1.cms.Attribute; 11 import org.bouncycastle.asn1.cms.AttributeTable; 12 import org.bouncycastle.asn1.cms.AuthenticatedData; 13 import org.bouncycastle.asn1.cms.CMSAlgorithmProtection; 14 import org.bouncycastle.asn1.cms.CMSAttributes; 15 import org.bouncycastle.asn1.cms.ContentInfo; 16 import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 17 import org.bouncycastle.operator.DigestCalculatorProvider; 18 import org.bouncycastle.operator.OperatorCreationException; 19 import org.bouncycastle.util.Arrays; 20 import org.bouncycastle.util.Encodable; 21 22 /** 23 * containing class for an CMS Authenticated Data object 24 */ 25 public class CMSAuthenticatedData 26 implements Encodable 27 { 28 RecipientInformationStore recipientInfoStore; 29 ContentInfo contentInfo; 30 31 private AlgorithmIdentifier macAlg; 32 private ASN1Set authAttrs; 33 private ASN1Set unauthAttrs; 34 private byte[] mac; 35 private OriginatorInformation originatorInfo; 36 CMSAuthenticatedData( byte[] authData)37 public CMSAuthenticatedData( 38 byte[] authData) 39 throws CMSException 40 { 41 this(CMSUtils.readContentInfo(authData)); 42 } 43 CMSAuthenticatedData( byte[] authData, DigestCalculatorProvider digestCalculatorProvider)44 public CMSAuthenticatedData( 45 byte[] authData, 46 DigestCalculatorProvider digestCalculatorProvider) 47 throws CMSException 48 { 49 this(CMSUtils.readContentInfo(authData), digestCalculatorProvider); 50 } 51 CMSAuthenticatedData( InputStream authData)52 public CMSAuthenticatedData( 53 InputStream authData) 54 throws CMSException 55 { 56 this(CMSUtils.readContentInfo(authData)); 57 } 58 CMSAuthenticatedData( InputStream authData, DigestCalculatorProvider digestCalculatorProvider)59 public CMSAuthenticatedData( 60 InputStream authData, 61 DigestCalculatorProvider digestCalculatorProvider) 62 throws CMSException 63 { 64 this(CMSUtils.readContentInfo(authData), digestCalculatorProvider); 65 } 66 CMSAuthenticatedData( ContentInfo contentInfo)67 public CMSAuthenticatedData( 68 ContentInfo contentInfo) 69 throws CMSException 70 { 71 this(contentInfo, null); 72 } 73 CMSAuthenticatedData( ContentInfo contentInfo, DigestCalculatorProvider digestCalculatorProvider)74 public CMSAuthenticatedData( 75 ContentInfo contentInfo, 76 DigestCalculatorProvider digestCalculatorProvider) 77 throws CMSException 78 { 79 this.contentInfo = contentInfo; 80 81 AuthenticatedData authData = AuthenticatedData.getInstance(contentInfo.getContent()); 82 83 if (authData.getOriginatorInfo() != null) 84 { 85 this.originatorInfo = new OriginatorInformation(authData.getOriginatorInfo()); 86 } 87 88 // 89 // read the recipients 90 // 91 ASN1Set recipientInfos = authData.getRecipientInfos(); 92 93 this.macAlg = authData.getMacAlgorithm(); 94 95 this.authAttrs = authData.getAuthAttrs(); 96 this.mac = authData.getMac().getOctets(); 97 this.unauthAttrs = authData.getUnauthAttrs(); 98 99 // 100 // read the authenticated content info 101 // 102 ContentInfo encInfo = authData.getEncapsulatedContentInfo(); 103 CMSReadable readable = new CMSProcessableByteArray( 104 encInfo.getContentType(), 105 ASN1OctetString.getInstance(encInfo.getContent()).getOctets()); 106 107 // 108 // build the RecipientInformationStore 109 // 110 if (authAttrs != null) 111 { 112 if (digestCalculatorProvider == null) 113 { 114 throw new CMSException("a digest calculator provider is required if authenticated attributes are present"); 115 } 116 117 AttributeTable table = new AttributeTable(authAttrs); 118 119 ASN1EncodableVector protectionAttributes = table.getAll(CMSAttributes.cmsAlgorithmProtect); 120 if (protectionAttributes.size() > 1) 121 { 122 throw new CMSException("Only one instance of a cmsAlgorithmProtect attribute can be present"); 123 } 124 125 if (protectionAttributes.size() > 0) 126 { 127 Attribute attr = Attribute.getInstance(protectionAttributes.get(0)); 128 if (attr.getAttrValues().size() != 1) 129 { 130 throw new CMSException("A cmsAlgorithmProtect attribute MUST contain exactly one value"); 131 } 132 133 CMSAlgorithmProtection algorithmProtection = CMSAlgorithmProtection.getInstance(attr.getAttributeValues()[0]); 134 135 if (!CMSUtils.isEquivalent(algorithmProtection.getDigestAlgorithm(), authData.getDigestAlgorithm())) 136 { 137 throw new CMSException("CMS Algorithm Identifier Protection check failed for digestAlgorithm"); 138 } 139 140 if (!CMSUtils.isEquivalent(algorithmProtection.getMacAlgorithm(), macAlg)) 141 { 142 throw new CMSException("CMS Algorithm Identifier Protection check failed for macAlgorithm"); 143 } 144 } 145 try 146 { 147 CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSDigestAuthenticatedSecureReadable(digestCalculatorProvider.get(authData.getDigestAlgorithm()), encInfo.getContentType(), readable); 148 149 this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(recipientInfos, this.macAlg, secureReadable, new AuthAttributesProvider() 150 { 151 public ASN1Set getAuthAttributes() 152 { 153 return authAttrs; 154 } 155 156 public boolean isAead() 157 { 158 return false; 159 } 160 }); 161 } 162 catch (OperatorCreationException e) 163 { 164 throw new CMSException("unable to create digest calculator: " + e.getMessage(), e); 165 } 166 } 167 else 168 { 169 CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSAuthenticatedSecureReadable(this.macAlg, encInfo.getContentType(), readable); 170 171 this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(recipientInfos, this.macAlg, secureReadable); 172 } 173 } 174 175 /** 176 * Return the originator information associated with this message if present. 177 * 178 * @return OriginatorInformation, null if not present. 179 */ getOriginatorInfo()180 public OriginatorInformation getOriginatorInfo() 181 { 182 return originatorInfo; 183 } 184 getMac()185 public byte[] getMac() 186 { 187 return Arrays.clone(mac); 188 } 189 encodeObj( ASN1Encodable obj)190 private byte[] encodeObj( 191 ASN1Encodable obj) 192 throws IOException 193 { 194 if (obj != null) 195 { 196 return obj.toASN1Primitive().getEncoded(); 197 } 198 199 return null; 200 } 201 202 /** 203 * Return the MAC algorithm details for the MAC associated with the data in this object. 204 * 205 * @return AlgorithmIdentifier representing the MAC algorithm. 206 */ getMacAlgorithm()207 public AlgorithmIdentifier getMacAlgorithm() 208 { 209 return macAlg; 210 } 211 212 /** 213 * return the object identifier for the content MAC algorithm. 214 */ getMacAlgOID()215 public String getMacAlgOID() 216 { 217 return macAlg.getAlgorithm().getId(); 218 } 219 220 /** 221 * return the ASN.1 encoded MAC algorithm parameters, or null if 222 * there aren't any. 223 */ getMacAlgParams()224 public byte[] getMacAlgParams() 225 { 226 try 227 { 228 return encodeObj(macAlg.getParameters()); 229 } 230 catch (Exception e) 231 { 232 throw new RuntimeException("exception getting encryption parameters " + e); 233 } 234 } 235 236 /** 237 * return a store of the intended recipients for this message 238 */ getRecipientInfos()239 public RecipientInformationStore getRecipientInfos() 240 { 241 return recipientInfoStore; 242 } 243 244 /** 245 * return the ContentInfo 246 * @deprecated use toASN1Structure() 247 */ getContentInfo()248 public ContentInfo getContentInfo() 249 { 250 return contentInfo; 251 } 252 253 /** 254 * return the ContentInfo 255 */ toASN1Structure()256 public ContentInfo toASN1Structure() 257 { 258 return contentInfo; 259 } 260 261 /** 262 * return a table of the digested attributes indexed by 263 * the OID of the attribute. 264 */ getAuthAttrs()265 public AttributeTable getAuthAttrs() 266 { 267 if (authAttrs == null) 268 { 269 return null; 270 } 271 272 return new AttributeTable(authAttrs); 273 } 274 275 /** 276 * return a table of the undigested attributes indexed by 277 * the OID of the attribute. 278 */ getUnauthAttrs()279 public AttributeTable getUnauthAttrs() 280 { 281 if (unauthAttrs == null) 282 { 283 return null; 284 } 285 286 return new AttributeTable(unauthAttrs); 287 } 288 289 /** 290 * return the ASN.1 encoded representation of this object. 291 */ getEncoded()292 public byte[] getEncoded() 293 throws IOException 294 { 295 return contentInfo.getEncoded(); 296 } 297 getContentDigest()298 public byte[] getContentDigest() 299 { 300 if (authAttrs != null) 301 { 302 return ASN1OctetString.getInstance(getAuthAttrs().get(CMSAttributes.messageDigest).getAttrValues().getObjectAt(0)).getOctets(); 303 } 304 305 return null; 306 } 307 } 308