SignerInformation(
      SignerInfo info,
      ASN1ObjectIdentifier contentType,
      CMSProcessable content,
      IntDigestCalculator digestCalculator,
      SignatureAlgorithmIdentifierFinder sigAlgFinder) {
    this.info = info;
    this.contentType = contentType;
    this.sigAlgFinder = sigAlgFinder;
    this.isCounterSignature = contentType == null;

    SignerIdentifier s = info.getSID();

    if (s.isTagged()) {
      ASN1OctetString octs = ASN1OctetString.getInstance(s.getId());

      sid = new SignerId(octs.getOctets());
    } else {
      IssuerAndSerialNumber iAnds = IssuerAndSerialNumber.getInstance(s.getId());

      sid = new SignerId(iAnds.getName(), iAnds.getSerialNumber().getValue());
    }

    this.digestAlgorithm = info.getDigestAlgorithm();
    this.signedAttributeSet = info.getAuthenticatedAttributes();
    this.unsignedAttributeSet = info.getUnauthenticatedAttributes();
    this.encryptionAlgorithm = info.getDigestEncryptionAlgorithm();
    this.signature = info.getEncryptedDigest().getOctets();

    this.content = content;
    this.digestCalculator = digestCalculator;
  }
  /** Tests the extension Freshest CRL DP. */
  @Test
  public void testCRLFreshestCRL() throws Exception {
    final String cdpURL = "http://www.ejbca.org/foo/bar.crl";
    final String freshestCdpURL = "http://www.ejbca.org/foo/delta.crl";
    X509CAInfo cainfo = (X509CAInfo) testx509ca.getCAInfo();
    X509CRL x509crl;
    byte[] cFreshestDpDER;

    cainfo.setUseCrlDistributionPointOnCrl(true);
    cainfo.setDefaultCRLDistPoint(cdpURL);
    cainfo.setCADefinedFreshestCRL(freshestCdpURL);
    caSession.editCA(roleMgmgToken, cainfo);
    publishingCrlSessionRemote.forceCRL(roleMgmgToken, testx509ca.getCAId());
    x509crl =
        CertTools.getCRLfromByteArray(crlStoreSession.getLastCRL(cainfo.getSubjectDN(), false));
    cFreshestDpDER = x509crl.getExtensionValue(Extension.freshestCRL.getId());
    assertNotNull("CRL has no Freshest Distribution Point", cFreshestDpDER);

    ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(cFreshestDpDER));
    ASN1OctetString octs = (ASN1OctetString) aIn.readObject();
    aIn = new ASN1InputStream(new ByteArrayInputStream(octs.getOctets()));
    CRLDistPoint cdp = CRLDistPoint.getInstance((ASN1Sequence) aIn.readObject());
    DistributionPoint[] distpoints = cdp.getDistributionPoints();

    assertEquals("More CRL Freshest distributions points than expected", 1, distpoints.length);
    assertEquals(
        "Freshest CRL distribution point is different",
        freshestCdpURL,
        ((DERIA5String)
                ((GeneralNames) distpoints[0].getDistributionPoint().getName())
                    .getNames()[0].getName())
            .getString());
  }
示例#3
0
 public byte[] getIV() {
   if (iv != null) {
     return iv.getOctets();
   } else {
     return null;
   }
 }
  private static ASN1Primitive getObject(String oid, byte[] ext) throws AnnotatedException {
    try {
      ASN1InputStream aIn = new ASN1InputStream(ext);
      ASN1OctetString octs = (ASN1OctetString) aIn.readObject();

      aIn = new ASN1InputStream(octs.getOctets());
      return aIn.readObject();
    } catch (Exception e) {
      throw new AnnotatedException("exception processing extension " + oid, e);
    }
  }
 /** Return an Extension ASN1Primitive from a CRL */
 protected static ASN1Primitive getExtensionValue(X509CRL crl, String oid) throws IOException {
   if (crl == null) {
     return null;
   }
   byte[] bytes = crl.getExtensionValue(oid);
   if (bytes == null) {
     return null;
   }
   ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(bytes));
   ASN1OctetString octs = (ASN1OctetString) aIn.readObject();
   aIn = new ASN1InputStream(new ByteArrayInputStream(octs.getOctets()));
   return aIn.readObject();
 } // getExtensionValue
 private byte[] getSubjectKeyId(X509Certificate cert) throws IOException {
   byte[] extvalue = cert.getExtensionValue(X509Extensions.SubjectKeyIdentifier.getId());
   if (extvalue == null) {
     return null;
   }
   ASN1OctetString str =
       ASN1OctetString.getInstance(
           new ASN1InputStream(new ByteArrayInputStream(extvalue)).readObject());
   SubjectKeyIdentifier keyId =
       SubjectKeyIdentifier.getInstance(
           new ASN1InputStream(new ByteArrayInputStream(str.getOctets())).readObject());
   return keyId.getKeyIdentifier();
 }
 private static boolean certHasPolicy(X509Certificate cert, String sOid) {
   try {
     if (m_logger.isDebugEnabled())
       m_logger.debug("Read cert policies: " + cert.getSerialNumber().toString());
     ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
     ASN1InputStream aIn = new ASN1InputStream(bIn);
     ASN1Sequence seq = (ASN1Sequence) aIn.readObject();
     X509CertificateStructure obj = new X509CertificateStructure(seq);
     TBSCertificateStructure tbsCert = obj.getTBSCertificate();
     if (tbsCert.getVersion() == 3) {
       X509Extensions ext = tbsCert.getExtensions();
       if (ext != null) {
         Enumeration en = ext.oids();
         while (en.hasMoreElements()) {
           DERObjectIdentifier oid = (DERObjectIdentifier) en.nextElement();
           X509Extension extVal = ext.getExtension(oid);
           ASN1OctetString oct = extVal.getValue();
           ASN1InputStream extIn = new ASN1InputStream(new ByteArrayInputStream(oct.getOctets()));
           // if (oid.equals(X509Extensions.CertificatePolicies)) { // bc 146 ja jdk 1.6 puhul -
           // X509Extension.certificatePolicies
           if (oid.equals(X509Extension.certificatePolicies)) { // bc 146 ja jdk 1.6 puhul -
             // X509Extension.certificatePolicies
             ASN1Sequence cp = (ASN1Sequence) extIn.readObject();
             for (int i = 0; i != cp.size(); i++) {
               PolicyInformation pol = PolicyInformation.getInstance(cp.getObjectAt(i));
               DERObjectIdentifier dOid = pol.getPolicyIdentifier();
               String soid2 = dOid.getId();
               if (m_logger.isDebugEnabled()) m_logger.debug("Policy: " + soid2);
               if (soid2.startsWith(sOid)) return true;
             }
           }
         }
       }
     }
   } catch (Exception ex) {
     m_logger.error("Error reading cert policies: " + ex);
   }
   return false;
 }
 /**
  * @return a list of URLs in String format with present freshest CRL extensions or an empty List
  */
 public static List<String> extractFreshestCrlDistributionPoints(final X509CRL crl) {
   final List<String> freshestCdpUrls = new ArrayList<String>();
   final byte[] extensionValue = crl.getExtensionValue(Extension.freshestCRL.getId());
   if (extensionValue != null) {
     final ASN1OctetString asn1OctetString =
         getAsn1ObjectFromBytes(extensionValue, ASN1OctetString.class);
     if (asn1OctetString != null) {
       final ASN1Sequence asn1Sequence =
           getAsn1ObjectFromBytes(asn1OctetString.getOctets(), ASN1Sequence.class);
       if (asn1Sequence != null) {
         final CRLDistPoint cdp = CRLDistPoint.getInstance(asn1Sequence);
         for (final DistributionPoint distributionPoint : cdp.getDistributionPoints()) {
           freshestCdpUrls.add(
               ((DERIA5String)
                       ((GeneralNames) distributionPoint.getDistributionPoint().getName())
                           .getNames()[0].getName())
                   .getString());
         }
       }
     }
   }
   return freshestCdpUrls;
 }
示例#9
0
  public static String toString(final ASN1OctetString value) {

    return new String(value.getOctets());
  }
示例#10
0
  @Override
  protected void onDocumentSigned(byte[] byteArray) {
    try {
      InputStream inputStream = new ByteArrayInputStream(byteArray);

      PDDocument document = PDDocument.load(inputStream);
      List<PDSignature> signatures = document.getSignatureDictionaries();
      assertEquals(1, signatures.size());

      for (PDSignature pdSignature : signatures) {
        byte[] contents = pdSignature.getContents(byteArray);
        byte[] signedContent = pdSignature.getSignedContent(byteArray);

        logger.info("Byte range : " + Arrays.toString(pdSignature.getByteRange()));

        // IOUtils.write(contents, new FileOutputStream("sig.p7s"));

        ASN1InputStream asn1sInput = new ASN1InputStream(contents);
        ASN1Sequence asn1Seq = (ASN1Sequence) asn1sInput.readObject();

        logger.info("SEQ : " + asn1Seq.toString());

        ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(asn1Seq.getObjectAt(0));
        assertEquals(PKCSObjectIdentifiers.signedData, oid);

        SignedData signedData =
            SignedData.getInstance(DERTaggedObject.getInstance(asn1Seq.getObjectAt(1)).getObject());

        ASN1Set digestAlgorithmSet = signedData.getDigestAlgorithms();
        ASN1ObjectIdentifier oidDigestAlgo =
            ASN1ObjectIdentifier.getInstance(
                ASN1Sequence.getInstance(digestAlgorithmSet.getObjectAt(0)).getObjectAt(0));
        DigestAlgorithm digestAlgorithm = DigestAlgorithm.forOID(oidDigestAlgo.getId());
        logger.info("DIGEST ALGO : " + digestAlgorithm);

        ContentInfo encapContentInfo = signedData.getEncapContentInfo();
        ASN1ObjectIdentifier contentTypeOID = encapContentInfo.getContentType();
        logger.info("ENCAPSULATED CONTENT INFO TYPE : " + contentTypeOID);
        assertEquals(PKCSObjectIdentifiers.data, contentTypeOID);

        ASN1Encodable content = encapContentInfo.getContent();
        logger.info("ENCAPSULATED CONTENT INFO CONTENT : " + content);
        assertNull(content);

        List<X509Certificate> certificates = extractCertificates(signedData);

        ASN1Set signerInfosAsn1 = signedData.getSignerInfos();
        logger.info("SIGNER INFO ASN1 : " + signerInfosAsn1.toString());
        SignerInfo signedInfo =
            SignerInfo.getInstance(ASN1Sequence.getInstance(signerInfosAsn1.getObjectAt(0)));

        ASN1Set authenticatedAttributeSet = signedInfo.getAuthenticatedAttributes();
        logger.info("AUTHENTICATED ATTR : " + authenticatedAttributeSet);

        List<ASN1ObjectIdentifier> attributeOids = new ArrayList<ASN1ObjectIdentifier>();
        for (int i = 0; i < authenticatedAttributeSet.size(); i++) {
          Attribute attribute = Attribute.getInstance(authenticatedAttributeSet.getObjectAt(i));
          attributeOids.add(attribute.getAttrType());
        }
        logger.info("List of OID for Auth Attrb : " + attributeOids);

        Attribute attributeDigest = Attribute.getInstance(authenticatedAttributeSet.getObjectAt(1));
        assertEquals(PKCSObjectIdentifiers.pkcs_9_at_messageDigest, attributeDigest.getAttrType());

        ASN1OctetString asn1ObjString =
            ASN1OctetString.getInstance(attributeDigest.getAttrValues().getObjectAt(0));
        String embeddedDigest = Base64.encode(asn1ObjString.getOctets());
        logger.info("MESSAGE DIGEST : " + embeddedDigest);

        byte[] digestSignedContent = DSSUtils.digest(digestAlgorithm, signedContent);
        String computedDigestSignedContentEncodeBase64 = Base64.encode(digestSignedContent);
        logger.info(
            "COMPUTED DIGEST SIGNED CONTENT BASE64 : " + computedDigestSignedContentEncodeBase64);
        assertEquals(embeddedDigest, computedDigestSignedContentEncodeBase64);

        SignerIdentifier sid = signedInfo.getSID();
        logger.info("SIGNER IDENTIFIER : " + sid.getId());

        IssuerAndSerialNumber issuerAndSerialNumber =
            IssuerAndSerialNumber.getInstance(signedInfo.getSID());
        ASN1Integer signerSerialNumber = issuerAndSerialNumber.getSerialNumber();
        logger.info(
            "ISSUER AND SN : " + issuerAndSerialNumber.getName() + " " + signerSerialNumber);

        BigInteger serial = issuerAndSerialNumber.getSerialNumber().getValue();
        X509Certificate signerCertificate = null;
        for (X509Certificate x509Certificate : certificates) {
          if (serial.equals(x509Certificate.getSerialNumber())) {
            signerCertificate = x509Certificate;
          }
        }
        assertNotNull(signerCertificate);

        String algorithm = signerCertificate.getPublicKey().getAlgorithm();
        EncryptionAlgorithm encryptionAlgorithm = EncryptionAlgorithm.forName(algorithm);

        ASN1OctetString encryptedInfoOctedString = signedInfo.getEncryptedDigest();
        String signatureValue = Hex.toHexString(encryptedInfoOctedString.getOctets());

        logger.info("SIGNATURE VALUE : " + signatureValue);

        Cipher cipher = Cipher.getInstance(encryptionAlgorithm.getName());
        cipher.init(Cipher.DECRYPT_MODE, signerCertificate);
        byte[] decrypted = cipher.doFinal(encryptedInfoOctedString.getOctets());

        ASN1InputStream inputDecrypted = new ASN1InputStream(decrypted);

        ASN1Sequence seqDecrypt = (ASN1Sequence) inputDecrypted.readObject();
        logger.info("DECRYPTED : " + seqDecrypt);

        DigestInfo digestInfo = new DigestInfo(seqDecrypt);
        assertEquals(oidDigestAlgo, digestInfo.getAlgorithmId().getAlgorithm());

        String decryptedDigestEncodeBase64 = Base64.encode(digestInfo.getDigest());
        logger.info("DECRYPTED BASE64 : " + decryptedDigestEncodeBase64);

        byte[] encoded = authenticatedAttributeSet.getEncoded();
        byte[] digest = DSSUtils.digest(digestAlgorithm, encoded);
        String computedDigestFromSignatureEncodeBase64 = Base64.encode(digest);
        logger.info(
            "COMPUTED DIGEST FROM SIGNATURE BASE64 : " + computedDigestFromSignatureEncodeBase64);

        assertEquals(decryptedDigestEncodeBase64, computedDigestFromSignatureEncodeBase64);

        IOUtils.closeQuietly(inputDecrypted);
        IOUtils.closeQuietly(asn1sInput);
      }

      IOUtils.closeQuietly(inputStream);
      document.close();
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
      fail(e.getMessage());
    }
  }
示例#11
0
  private boolean doVerify(SignerInformationVerifier verifier) throws CMSException {
    String digestName = CMSSignedHelper.INSTANCE.getDigestAlgName(this.getDigestAlgOID());
    String encName = CMSSignedHelper.INSTANCE.getEncryptionAlgName(this.getEncryptionAlgOID());
    String signatureName = digestName + "with" + encName;

    try {
      if (digestCalculator != null) {
        resultDigest = digestCalculator.getDigest();
      } else {
        DigestCalculator calc = verifier.getDigestCalculator(this.getDigestAlgorithmID());
        if (content != null) {
          OutputStream digOut = calc.getOutputStream();

          content.write(digOut);

          digOut.close();
        } else if (signedAttributeSet == null) {
          // TODO Get rid of this exception and just treat content==null as empty not missing?
          throw new CMSException("data not encapsulated in signature - use detached constructor.");
        }

        resultDigest = calc.getDigest();
      }
    } catch (IOException e) {
      throw new CMSException("can't process mime object to create signature.", e);
    } catch (NoSuchAlgorithmException e) {
      throw new CMSException("can't find algorithm: " + e.getMessage(), e);
    } catch (OperatorCreationException e) {
      throw new CMSException("can't create digest calculator: " + e.getMessage(), e);
    }

    // RFC 3852 11.1 Check the content-type attribute is correct
    {
      DERObject validContentType =
          getSingleValuedSignedAttribute(CMSAttributes.contentType, "content-type");
      if (validContentType == null) {
        if (!isCounterSignature && signedAttributeSet != null) {
          throw new CMSException(
              "The content-type attribute type MUST be present whenever signed attributes are present in signed-data");
        }
      } else {
        if (isCounterSignature) {
          throw new CMSException(
              "[For counter signatures,] the signedAttributes field MUST NOT contain a content-type attribute");
        }

        if (!(validContentType instanceof DERObjectIdentifier)) {
          throw new CMSException(
              "content-type attribute value not of ASN.1 type 'OBJECT IDENTIFIER'");
        }

        DERObjectIdentifier signedContentType = (DERObjectIdentifier) validContentType;

        if (!signedContentType.equals(contentType)) {
          throw new CMSException("content-type attribute value does not match eContentType");
        }
      }
    }

    // RFC 3852 11.2 Check the message-digest attribute is correct
    {
      DERObject validMessageDigest =
          getSingleValuedSignedAttribute(CMSAttributes.messageDigest, "message-digest");
      if (validMessageDigest == null) {
        if (signedAttributeSet != null) {
          throw new CMSException(
              "the message-digest signed attribute type MUST be present when there are any signed attributes present");
        }
      } else {
        if (!(validMessageDigest instanceof ASN1OctetString)) {
          throw new CMSException("message-digest attribute value not of ASN.1 type 'OCTET STRING'");
        }

        ASN1OctetString signedMessageDigest = (ASN1OctetString) validMessageDigest;

        if (!Arrays.constantTimeAreEqual(resultDigest, signedMessageDigest.getOctets())) {
          throw new CMSSignerDigestMismatchException(
              "message-digest attribute value does not match calculated value");
        }
      }
    }

    // RFC 3852 11.4 Validate countersignature attribute(s)
    {
      AttributeTable signedAttrTable = this.getSignedAttributes();
      if (signedAttrTable != null
          && signedAttrTable.getAll(CMSAttributes.counterSignature).size() > 0) {
        throw new CMSException("A countersignature attribute MUST NOT be a signed attribute");
      }

      AttributeTable unsignedAttrTable = this.getUnsignedAttributes();
      if (unsignedAttrTable != null) {
        ASN1EncodableVector csAttrs = unsignedAttrTable.getAll(CMSAttributes.counterSignature);
        for (int i = 0; i < csAttrs.size(); ++i) {
          Attribute csAttr = (Attribute) csAttrs.get(i);
          if (csAttr.getAttrValues().size() < 1) {
            throw new CMSException(
                "A countersignature attribute MUST contain at least one AttributeValue");
          }

          // Note: We don't recursively validate the countersignature value
        }
      }
    }

    try {
      ContentVerifier contentVerifier =
          verifier.getContentVerifier(sigAlgFinder.find(signatureName));
      OutputStream sigOut = contentVerifier.getOutputStream();

      if (signedAttributeSet == null) {
        if (digestCalculator != null) {
          if (contentVerifier instanceof RawContentVerifier) {
            RawContentVerifier rawVerifier = (RawContentVerifier) contentVerifier;

            if (encName.equals("RSA")) {
              DigestInfo digInfo = new DigestInfo(digestAlgorithm, resultDigest);

              return rawVerifier.verify(digInfo.getDEREncoded(), this.getSignature());
            }

            return rawVerifier.verify(resultDigest, this.getSignature());
          }

          throw new CMSException("verifier unable to process raw signature");
        } else if (content != null) {
          // TODO Use raw signature of the hash value instead
          content.write(sigOut);
        }
      } else {
        sigOut.write(this.getEncodedSignedAttributes());
      }

      sigOut.close();

      return contentVerifier.verify(this.getSignature());
    } catch (IOException e) {
      throw new CMSException("can't process mime object to create signature.", e);
    } catch (OperatorCreationException e) {
      throw new CMSException("can't create content verifier: " + e.getMessage(), e);
    }
  }
示例#12
0
  /** @deprecated */
  private boolean doVerify(PublicKey key, Provider sigProvider)
      throws CMSException, NoSuchAlgorithmException {
    String digestName = CMSSignedHelper.INSTANCE.getDigestAlgName(this.getDigestAlgOID());
    String encName = CMSSignedHelper.INSTANCE.getEncryptionAlgName(this.getEncryptionAlgOID());
    String signatureName = digestName + "with" + encName;
    Signature sig = CMSSignedHelper.INSTANCE.getSignatureInstance(signatureName, sigProvider);
    MessageDigest digest = CMSSignedHelper.INSTANCE.getDigestInstance(digestName, sigProvider);

    // TODO [BJA-109] Note: PSSParameterSpec requires JDK1.4+
    /*
            try
            {
                DERObjectIdentifier sigAlgOID = encryptionAlgorithm.getObjectId();
                DEREncodable sigParams = this.encryptionAlgorithm.getParameters();
                if (sigAlgOID.equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
                {
                    // RFC 4056
                    // When the id-RSASSA-PSS algorithm identifier is used for a signature,
                    // the AlgorithmIdentifier parameters field MUST contain RSASSA-PSS-params.
                    if (sigParams == null)
                    {
                        throw new CMSException(
                            "RSASSA-PSS signature must specify algorithm parameters");
                    }

                    AlgorithmParameters params = AlgorithmParameters.getInstance(
                        sigAlgOID.getId(), sig.getProvider().getName());
                    params.init(sigParams.getDERObject().getEncoded(), "ASN.1");

                    PSSParameterSpec spec = (PSSParameterSpec)params.getParameterSpec(PSSParameterSpec.class);
                    sig.setParameter(spec);
                }
                else
                {
                    // TODO Are there other signature algorithms that provide parameters?
                    if (sigParams != null)
                    {
                        throw new CMSException("unrecognised signature parameters provided");
                    }
                }
            }
            catch (IOException e)
            {
                throw new CMSException("error encoding signature parameters.", e);
            }
            catch (InvalidAlgorithmParameterException e)
            {
                throw new CMSException("error setting signature parameters.", e);
            }
            catch (InvalidParameterSpecException e)
            {
                throw new CMSException("error processing signature parameters.", e);
            }
    */

    try {
      if (digestCalculator != null) {
        resultDigest = digestCalculator.getDigest();
      } else {
        if (content != null) {
          content.write(new DigOutputStream(digest));
        } else if (signedAttributeSet == null) {
          // TODO Get rid of this exception and just treat content==null as empty not missing?
          throw new CMSException("data not encapsulated in signature - use detached constructor.");
        }

        resultDigest = digest.digest();
      }
    } catch (IOException e) {
      throw new CMSException("can't process mime object to create signature.", e);
    }

    // RFC 3852 11.1 Check the content-type attribute is correct
    {
      DERObject validContentType =
          getSingleValuedSignedAttribute(CMSAttributes.contentType, "content-type");
      if (validContentType == null) {
        if (!isCounterSignature && signedAttributeSet != null) {
          throw new CMSException(
              "The content-type attribute type MUST be present whenever signed attributes are present in signed-data");
        }
      } else {
        if (isCounterSignature) {
          throw new CMSException(
              "[For counter signatures,] the signedAttributes field MUST NOT contain a content-type attribute");
        }

        if (!(validContentType instanceof DERObjectIdentifier)) {
          throw new CMSException(
              "content-type attribute value not of ASN.1 type 'OBJECT IDENTIFIER'");
        }

        DERObjectIdentifier signedContentType = (DERObjectIdentifier) validContentType;

        if (!signedContentType.equals(contentType)) {
          throw new CMSException("content-type attribute value does not match eContentType");
        }
      }
    }

    // RFC 3852 11.2 Check the message-digest attribute is correct
    {
      DERObject validMessageDigest =
          getSingleValuedSignedAttribute(CMSAttributes.messageDigest, "message-digest");
      if (validMessageDigest == null) {
        if (signedAttributeSet != null) {
          throw new CMSException(
              "the message-digest signed attribute type MUST be present when there are any signed attributes present");
        }
      } else {
        if (!(validMessageDigest instanceof ASN1OctetString)) {
          throw new CMSException("message-digest attribute value not of ASN.1 type 'OCTET STRING'");
        }

        ASN1OctetString signedMessageDigest = (ASN1OctetString) validMessageDigest;

        if (!Arrays.constantTimeAreEqual(resultDigest, signedMessageDigest.getOctets())) {
          throw new CMSSignerDigestMismatchException(
              "message-digest attribute value does not match calculated value");
        }
      }
    }

    // RFC 3852 11.4 Validate countersignature attribute(s)
    {
      AttributeTable signedAttrTable = this.getSignedAttributes();
      if (signedAttrTable != null
          && signedAttrTable.getAll(CMSAttributes.counterSignature).size() > 0) {
        throw new CMSException("A countersignature attribute MUST NOT be a signed attribute");
      }

      AttributeTable unsignedAttrTable = this.getUnsignedAttributes();
      if (unsignedAttrTable != null) {
        ASN1EncodableVector csAttrs = unsignedAttrTable.getAll(CMSAttributes.counterSignature);
        for (int i = 0; i < csAttrs.size(); ++i) {
          Attribute csAttr = (Attribute) csAttrs.get(i);
          if (csAttr.getAttrValues().size() < 1) {
            throw new CMSException(
                "A countersignature attribute MUST contain at least one AttributeValue");
          }

          // Note: We don't recursively validate the countersignature value
        }
      }
    }

    try {
      sig.initVerify(key);

      if (signedAttributeSet == null) {
        if (digestCalculator != null) {
          // need to decrypt signature and check message bytes
          return verifyDigest(resultDigest, key, this.getSignature(), sigProvider);
        } else if (content != null) {
          // TODO Use raw signature of the hash value instead
          content.write(new SigOutputStream(sig));
        }
      } else {
        sig.update(this.getEncodedSignedAttributes());
      }

      return sig.verify(this.getSignature());
    } catch (InvalidKeyException e) {
      throw new CMSException("key not appropriate to signature in message.", e);
    } catch (IOException e) {
      throw new CMSException("can't process mime object to create signature.", e);
    } catch (SignatureException e) {
      throw new CMSException("invalid signature format in message: " + e.getMessage(), e);
    }
  }