--- src_unitTests/org/apache/xml/security/test/AllTests.java.sav	2005-04-02 14:16:49.000000000 -0500
+++ src_unitTests/org/apache/xml/security/test/AllTests.java	2009-10-27 13:36:17.000000000 -0400
@@ -53,6 +53,7 @@ public class AllTests extends TestCase {
       //J-
       suite.addTest(org.apache.xml.security.test.ModuleTest.suite());
       suite.addTest(org.apache.xml.security.test.InteropTest.suite());
+      suite.addTest(org.apache.xml.security.test.signature.HMACOutputLengthTest.suite());
       //J+
 
       return suite;
--- src_unitTests/org/apache/xml/security/test/interop/BaltimoreTest.java.sav	2004-05-18 07:42:33.000000000 -0400
+++ src_unitTests/org/apache/xml/security/test/interop/BaltimoreTest.java	2009-10-27 13:36:21.000000000 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright  1999-2004 The Apache Software Foundation.
+ * Copyright 1999-2009 The Apache Software Foundation.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -16,14 +16,12 @@
  */
 package org.apache.xml.security.test.interop;
 
-
-
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
 import org.apache.xml.security.test.utils.resolver.OfflineResolver;
 import org.apache.xml.security.utils.resolver.ResourceResolverSpi;
-
+import org.apache.xml.security.signature.XMLSignatureException;
 
 /**
  * This test is to ensure interoperability with the examples provided by Merlin Huges
@@ -112,16 +110,17 @@ public class BaltimoreTest extends Inter
 
       try {
          verify = this.verifyHMAC(filename, resolver, followManifests, hmacKey);
+         fail("HMACOutputLength Exception not caught");
       } catch (RuntimeException ex) {
          log.error("Verification crashed for " + filename);
          throw ex;
+      } catch (XMLSignatureException ex) {
+         if (ex.getMsgID().equals("algorithms.HMACOutputLengthMin")) {
+             // succeed
+         } else {
+             fail(ex.getMessage());
+         }
       }
-
-      if (!verify) {
-         log.error("Verification failed for " + filename);
-      }
-
-      assertTrue(filename, verify);
    }
 
    /**
@@ -341,16 +340,17 @@ public class BaltimoreTest extends Inter
 
       try {
          verify = this.verifyHMAC(filename, resolver, followManifests, hmacKey);
+         fail("HMACOutputLength Exception not caught");
       } catch (RuntimeException ex) {
          log.error("Verification crashed for " + filename);
          throw ex;
+      } catch (XMLSignatureException ex) {
+         if (ex.getMsgID().equals("algorithms.HMACOutputLengthMin")) {
+             // succeed
+         } else {
+             fail(ex.getMessage());
+         }
       }
-
-      if (!verify) {
-         log.error("Verification failed for " + filename);
-      }
-
-      assertTrue(filename, verify);
    }
 
    /**
--- src_unitTests/org/apache/xml/security/test/interop/IAIKTest.java.sav	2004-02-08 01:08:22.000000000 -0500
+++ src_unitTests/org/apache/xml/security/test/interop/IAIKTest.java	2009-10-27 13:36:24.000000000 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright  1999-2004 The Apache Software Foundation.
+ * Copyright 1999-2009 The Apache Software Foundation.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -16,16 +16,14 @@
  */
 package org.apache.xml.security.test.interop;
 
-
-
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
 import org.apache.xml.security.test.utils.resolver.OfflineResolver;
+import org.apache.xml.security.signature.XMLSignatureException;
 import org.apache.xml.security.utils.resolver.ResourceResolverSpi;
 import org.apache.xml.security.utils.resolver.implementations.ResolverAnonymous;
 
-
 /**
  * This test is to ensure interoperability with the examples provided by the IAIK
  * XML Signature implementation. Thanks to Gregor Karlinger who provided these
@@ -94,17 +92,17 @@ public class IAIKTest extends InteropTes
 
       try {
          verify = this.verifyHMAC(filename, resolver, followManifests, hmacKey);
+         fail("HMACOutputLength Exception not caught");
       } catch (RuntimeException ex) {
          log.error("Verification crashed for " + filename);
-
          throw ex;
+      } catch (XMLSignatureException ex) {
+         if (ex.getMsgID().equals("algorithms.HMACOutputLengthMin")) {
+             // succeed
+         } else {
+             fail(ex.getMessage());
+         }
       }
-
-      if (!verify) {
-         log.error("Verification failed for " + filename);
-      }
-
-      assertTrue(filename, verify);
    }
 
    /**
--- src/org/apache/xml/security/signature/XMLSignature.java.sav	2005-04-03 07:30:33.000000000 -0400
+++ src/org/apache/xml/security/signature/XMLSignature.java	2009-10-27 13:36:30.000000000 -0400
@@ -510,6 +510,8 @@ public final class XMLSignature extends 
             // set them on the SignateValue element
             this.setSignatureValueElement(jcebytes);
          }
+      } catch (XMLSignatureException ex) {
+         throw ex;
       } catch (CanonicalizationException ex) {
          throw new XMLSignatureException("empty", ex);
       } catch (InvalidCanonicalizerException ex) {
@@ -624,6 +626,8 @@ public final class XMLSignature extends 
          boolean verify = sa.verify(sigBytes);
 
          return verify;
+      } catch (XMLSignatureException ex) {
+         throw ex;
       } catch (XMLSecurityException ex) {
          throw new XMLSignatureException("empty", ex);
       } 
--- src/org/apache/xml/security/resource/xmlsecurity_de.properties.sav	2009-10-27 13:40:16.000000000 -0400
+++ src/org/apache/xml/security/resource/xmlsecurity_de.properties	2009-10-27 13:36:31.000000000 -0400
@@ -5,6 +5,7 @@ algorithm.extendsWrongClass = Kann URI {
 algorithms.CannotUseAlgorithmParameterSpecOnDSA = Sorry, but you cannot use a AlgorithmParameterSpec object for creating DSA signatures.
 algorithms.CannotUseAlgorithmParameterSpecOnRSA = Sorry, but you cannot use a AlgorithmParameterSpec object for creating RSA signatures.
 algorithms.CannotUseSecureRandomOnMAC = Sorry, but you cannot use a SecureRandom object for creating MACs.
+algorithms.HMACOutputLengthMin = HMACOutputLength must not be less than {0}
 algorithms.HMACOutputLengthOnlyForHMAC = A HMACOutputLength can only be specified for HMAC integrity algorithms
 algorithms.NoSuchAlgorithm = Der Algorithmus {0} ist nicht verfügbar. Original Nachricht war: {1}
 algorithms.NoSuchMap = The algorithm URI "{0}" could not be mapped to a JCE algorithm
--- src/org/apache/xml/security/resource/xmlsecurity_en.properties.sav	2009-10-27 13:40:36.000000000 -0400
+++ src/org/apache/xml/security/resource/xmlsecurity_en.properties	2009-10-27 13:53:58.000000000 -0400
@@ -5,6 +5,7 @@ algorithm.extendsWrongClass = Cannot reg
 algorithms.CannotUseAlgorithmParameterSpecOnDSA = Sorry, but you cannot use a AlgorithmParameterSpec object for creating DSA signatures.
 algorithms.CannotUseAlgorithmParameterSpecOnRSA = Sorry, but you cannot use a AlgorithmParameterSpec object for creating RSA signatures.
 algorithms.CannotUseSecureRandomOnMAC = Sorry, but you cannot use a SecureRandom object for creating MACs.
+algorithms.HMACOutputLengthMin = HMACOutputLength must not be less than {0}
 algorithms.HMACOutputLengthOnlyForHMAC = A HMACOutputLength can only be specified for HMAC integrity algorithms
 algorithms.NoSuchAlgorithm = The requested algorithm {0} does not exist. Original Message was: {1}
 algorithms.NoSuchMap = The algorithm URI "{0}" could not be mapped to a JCE algorithm
--- data/javax/xml/crypto/dsig/signature-enveloping-hmac-sha1-trunclen-0-attack.xml.sav	2009-10-27 13:57:32.000000000 -0400
+++ data/javax/xml/crypto/dsig/signature-enveloping-hmac-sha1-trunclen-0-attack.xml	2009-10-27 13:58:18.000000000 -0400
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
+  <SignedInfo>
+    <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
+    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1">
+      <HMACOutputLength>0</HMACOutputLength>
+    </SignatureMethod>
+    <Reference URI="#object">
+      <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
+      <DigestValue>nz4GS0NbH2SrWlD/4fX313CoTzc=</DigestValue>
+    </Reference>
+  </SignedInfo>
+  <SignatureValue>
+  </SignatureValue>
+  <Object Id="object">some other text</Object>
+</Signature>
--- src/org/apache/xml/security/algorithms/implementations/IntegrityHmac.java.orig	2005-04-02 13:48:37.000000000 -0500
+++ src/org/apache/xml/security/algorithms/implementations/IntegrityHmac.java	2009-10-28 09:48:06.000000000 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright  1999-2004 The Apache Software Foundation.
+ * Copyright  1999-2009 The Apache Software Foundation.
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -56,11 +56,17 @@ public abstract class IntegrityHmac exte
     */
    public abstract String engineGetURI();
 
+   /**
+    * Returns the output length of the hash/digest.
+    */
+   abstract int getDigestLength();
+
    /** Field _macAlgorithm */
    private Mac _macAlgorithm = null;
 
    /** Field _HMACOutputLength */
    int _HMACOutputLength = 0;
+   private boolean _HMACOutputLengthSet = false;
 
    /**
     * Method IntegrityHmacSHA1das
@@ -83,6 +89,12 @@ public abstract class IntegrityHmac exte
       }
    }
 
+    public void reset() {
+       _HMACOutputLength=0;
+       _HMACOutputLengthSet = false;
+       this._macAlgorithm.reset();
+    }
+
    /**
     * Proxy method for {@link java.security.Signature#setParameter(java.security.spec.AlgorithmParameterSpec)}
     * which is executed on the internal {@link java.security.Signature} object.
@@ -107,14 +119,18 @@ public abstract class IntegrityHmac exte
            throws XMLSignatureException {
 
       try {
-         byte[] completeResult = this._macAlgorithm.doFinal();
-
-         if ((this._HMACOutputLength == 0) || (this._HMACOutputLength >= 160)) {
+         if (this._HMACOutputLengthSet && this._HMACOutputLength < getDigestLength())
+         {
+            if (log.isDebugEnabled()) {
+                log.debug("HMACOutputLength must not be less than " + getDigestLength());
+            }
+            Object[] exArgs = { String.valueOf(getDigestLength()) };
+            throw new XMLSignatureException
+                ("algorithms.HMACOutputLengthMin", exArgs);
+         } else {
+            byte[] completeResult = this._macAlgorithm.doFinal();
             return MessageDigestAlgorithm.isEqual(completeResult, signature);
          }
-         byte[] stripped = IntegrityHmac.reduceBitLength(completeResult,
-                                 this._HMACOutputLength);
-         return MessageDigestAlgorithm.isEqual(stripped, signature);         
       } catch (IllegalStateException ex) {
          throw new XMLSignatureException("empty", ex);
       }
@@ -155,14 +171,16 @@ public abstract class IntegrityHmac exte
    protected byte[] engineSign() throws XMLSignatureException {
 
       try {
-         byte[] completeResult = this._macAlgorithm.doFinal();
-
-         if ((this._HMACOutputLength == 0) || (this._HMACOutputLength >= 160)) {
-            return completeResult;
-         } 
-          return IntegrityHmac.reduceBitLength(completeResult,
-                                                 this._HMACOutputLength);
-         
+         if (this._HMACOutputLengthSet && this._HMACOutputLength < getDigestLength()) {
+            if (log.isDebugEnabled()) {
+                log.debug("HMACOutputLength must not be less than " + getDigestLength());
+            }
+            Object[] exArgs = { String.valueOf(getDigestLength()) };
+            throw new XMLSignatureException
+                ("algorithms.HMACOutputLengthMin", exArgs);
+         } else {
+            return this._macAlgorithm.doFinal();
+         }
       } catch (IllegalStateException ex) {
          throw new XMLSignatureException("empty", ex);
       }
@@ -340,6 +358,7 @@ public abstract class IntegrityHmac exte
     */
    protected void engineSetHMACOutputLength(int HMACOutputLength) {
       this._HMACOutputLength = HMACOutputLength;
+      this._HMACOutputLengthSet = true;
    }
 
    /**
@@ -355,12 +374,13 @@ public abstract class IntegrityHmac exte
          throw new IllegalArgumentException("element null");
       }
 
-             Text hmaclength =XMLUtils.selectDsNodeText(element.getFirstChild(),
-                    Constants._TAG_HMACOUTPUTLENGTH,0);               
+      Text hmaclength =XMLUtils.selectDsNodeText(element.getFirstChild(),
+         Constants._TAG_HMACOUTPUTLENGTH,0);     
 
-            if (hmaclength != null) {
-               this._HMACOutputLength = Integer.parseInt(hmaclength.getData());
-            }
+      if (hmaclength != null) {
+         this._HMACOutputLength = Integer.parseInt(hmaclength.getData());
+         this._HMACOutputLengthSet = true;
+      }
       
    }
 
@@ -369,14 +389,13 @@ public abstract class IntegrityHmac exte
     *
     * @param element
     */
-   public void engineAddContextToElement(Element element)
-           {
+   public void engineAddContextToElement(Element element) {
 
       if (element == null) {
          throw new IllegalArgumentException("null element");
       }
 
-      if (this._HMACOutputLength != 0) {
+      if (this._HMACOutputLengthSet) {
          Document doc = element.getOwnerDocument();
          Element HMElem = XMLUtils.createElementInSignatureSpace(doc,
                              Constants._TAG_HMACOUTPUTLENGTH);
@@ -415,6 +434,10 @@ public abstract class IntegrityHmac exte
       public String engineGetURI() {
          return XMLSignature.ALGO_ID_MAC_HMAC_SHA1;
       }
+
+      int getDigestLength() {
+          return 160;
+      }
    }
 
    /**
@@ -442,6 +465,10 @@ public abstract class IntegrityHmac exte
       public String engineGetURI() {
          return XMLSignature.ALGO_ID_MAC_HMAC_SHA256;
       }
+
+      int getDigestLength() {
+          return 256;
+      }
    }
 
    /**
@@ -469,6 +496,10 @@ public abstract class IntegrityHmac exte
       public String engineGetURI() {
          return XMLSignature.ALGO_ID_MAC_HMAC_SHA384;
       }
+
+      int getDigestLength() {
+          return 384;
+      }
    }
 
    /**
@@ -496,6 +527,10 @@ public abstract class IntegrityHmac exte
       public String engineGetURI() {
          return XMLSignature.ALGO_ID_MAC_HMAC_SHA512;
       }
+
+      int getDigestLength() {
+          return 512;
+      }
    }
 
    /**
@@ -523,6 +558,10 @@ public abstract class IntegrityHmac exte
       public String engineGetURI() {
          return XMLSignature.ALGO_ID_MAC_HMAC_RIPEMD160;
       }
+
+      int getDigestLength() {
+          return 160;
+      }
    }
 
    /**
@@ -550,5 +589,9 @@ public abstract class IntegrityHmac exte
       public String engineGetURI() {
          return XMLSignature.ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5;
       }
+
+      int getDigestLength() {
+          return 128;
+      }
    }
 }
--- data/javax/xml/crypto/dsig/signature-enveloping-hmac-sha1-trunclen-8-attack.xml.orig
+++ data/javax/xml/crypto/dsig/signature-enveloping-hmac-sha1-trunclen-8-attack.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
+  <SignedInfo>
+    <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
+    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1">
+      <HMACOutputLength>8</HMACOutputLength>
+    </SignatureMethod>
+    <Reference URI="#object">
+      <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
+      <DigestValue>nz4GS0NbH2SrWlD/4fX313CoTzc=</DigestValue>
+    </Reference>
+  </SignedInfo>
+  <SignatureValue>
+    Qw==
+  </SignatureValue>
+  <Object Id="object">some other text</Object>
+</Signature>
\ No newline at end of file
--- src_unitTests/org/apache/xml/security/test/signature/HMACOutputLengthTest.java.orig	2009-07-27 13:30:08.000000000 +0200
+++ src_unitTests/org/apache/xml/security/test/signature/HMACOutputLengthTest.java	        2009-07-24 10:48:06.000000000 +0200
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2009 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.xml.security.test.signature;
+
+import java.io.File;
+import javax.crypto.SecretKey;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.apache.xml.security.Init;
+import org.apache.xml.security.c14n.Canonicalizer;
+import org.apache.xml.security.signature.XMLSignature;
+import org.apache.xml.security.signature.XMLSignatureException;
+import org.apache.xml.security.utils.Constants;
+
+public class HMACOutputLengthTest extends TestCase {
+
+    private static DocumentBuilderFactory dbf = null;
+
+    protected void setUp() throws Exception {
+        Init.init();
+        dbf = DocumentBuilderFactory.newInstance();
+        dbf.setNamespaceAware(true);
+        dbf.setValidating(false);
+    }
+
+    /** {@link org.apache.commons.logging} logging facility */
+    static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog
+            (HMACOutputLengthTest.class.getName());
+
+    private static final String BASEDIR = System.getProperty("basedir");
+    private static final String SEP = System.getProperty("file.separator");
+
+    public static Test suite() {
+        return new TestSuite(HMACOutputLengthTest.class);
+    }
+
+    public HMACOutputLengthTest(String name) {
+        super(name);
+    }
+
+    public static void main(String[] args) {
+        String[] testCaseName = { "-noloading",
+                                  HMACOutputLengthTest.class.getName() };
+
+        junit.textui.TestRunner.main(testCaseName);
+    }
+
+    public void test_signature_enveloping_hmac_sha1_trunclen_0() throws Exception {
+        try {
+            validate("signature-enveloping-hmac-sha1-trunclen-0-attack.xml");
+            fail("Expected HMACOutputLength exception");
+        } catch (XMLSignatureException xse) {
+            System.out.println(xse.getMessage());
+            if (xse.getMsgID().equals("algorithms.HMACOutputLengthMin")) {
+                // pass
+            } else {
+                fail(xse.getMessage());
+            }
+        }
+    }
+    public void test_signature_enveloping_hmac_sha1_trunclen_8() throws Exception {
+        try {
+            validate("signature-enveloping-hmac-sha1-trunclen-8-attack.xml");
+        } catch (XMLSignatureException xse) {
+            System.out.println(xse.getMessage());
+            if (xse.getMsgID().equals("algorithms.HMACOutputLengthMin")) {
+                // pass
+            } else {
+                fail(xse.getMessage());
+            }
+        }
+    }
+
+    private static void validate(String data) throws Exception {
+        System.out.println("Validating " + data);
+        File file = new File(BASEDIR + SEP + "data" + SEP + "javax" + SEP + "xml" + SEP + "crypto" + SEP + "dsig" + SEP, data);
+
+        Document doc = dbf.newDocumentBuilder().parse(file);
+        NodeList nl =
+            doc.getElementsByTagNameNS(Constants.SignatureSpecNS, "Signature");
+        if (nl.getLength() == 0) {
+            throw new Exception("Couldn't find signature Element");
+        }
+        Element sigElement = (Element) nl.item(0);
+        XMLSignature signature = new XMLSignature
+            (sigElement, file.toURI().toString());
+        SecretKey sk = signature.createSecretKey("secret".getBytes("ASCII"));
+        System.out.println
+            ("Validation status: " + signature.checkSignatureValue(sk));
+    }
+
+    public void test_generate_hmac_sha1_40() throws Exception {
+        System.out.println("Generating ");
+
+        Document doc = dbf.newDocumentBuilder().newDocument();
+        XMLSignature sig = new XMLSignature
+            (doc, null, XMLSignature.ALGO_ID_MAC_HMAC_SHA1, 40,
+             Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
+        try {
+            sig.sign(getSecretKey("secret".getBytes("ASCII")));
+            fail("Expected HMACOutputLength Exception");
+        } catch (XMLSignatureException xse) {
+            System.out.println(xse.getMessage());
+            if (xse.getMsgID().equals("algorithms.HMACOutputLengthMin")) {
+                // pass
+            } else {
+                fail(xse.getMessage());
+            }
+        }
+    }
+
+    private static SecretKey getSecretKey(final byte[] secret) {
+        return new SecretKey() {
+            public String getFormat()   { return "RAW"; }
+            public byte[] getEncoded()  { return secret; }
+            public String getAlgorithm(){ return "SECRET"; }
+        };
+    }
+}
