1 /*
   2  * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  * @test %I% %E%
  26  * @bug 6824440 6858484
  27  * @summary Check that Apache XMLSec APIs will not accept HMAC truncation
  28  *    lengths less than minimum bound
  29  * @compile -XDignore.symbol.file TruncateHMAC.java
  30  * @run main TruncateHMAC
  31  */
  32 
  33 import java.io.File;
  34 import javax.crypto.SecretKey;
  35 import javax.xml.parsers.DocumentBuilderFactory;
  36 import org.w3c.dom.Document;
  37 import org.w3c.dom.Element;
  38 import org.w3c.dom.NodeList;
  39 
  40 import com.sun.org.apache.xml.internal.security.Init;
  41 import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer;
  42 import com.sun.org.apache.xml.internal.security.signature.XMLSignature;
  43 import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException;
  44 import com.sun.org.apache.xml.internal.security.utils.Constants;
  45 
  46 
  47 public class TruncateHMAC {
  48 
  49     private final static String DIR = System.getProperty("test.src", ".");
  50     private static DocumentBuilderFactory dbf = null;
  51     private static boolean atLeastOneFailed = false;
  52 
  53     public static void main(String[] args) throws Exception {
  54 
  55         Init.init();
  56         dbf = DocumentBuilderFactory.newInstance();
  57         dbf.setNamespaceAware(true);
  58         dbf.setValidating(false);
  59         validate("signature-enveloping-hmac-sha1-trunclen-0-attack.xml", false);
  60         validate("signature-enveloping-hmac-sha1-trunclen-8-attack.xml", false);
  61         // this one should pass
  62         validate("signature-enveloping-hmac-sha1.xml", true);
  63         generate_hmac_sha1_40();
  64 
  65         if (atLeastOneFailed) {
  66             throw new Exception
  67                 ("At least one signature did not validate as expected");
  68         }
  69     }
  70 
  71     private static void validate(String data, boolean pass) throws Exception {
  72         System.out.println("Validating " + data);
  73         File file = new File(DIR, data);
  74 
  75         Document doc = dbf.newDocumentBuilder().parse(file);
  76         NodeList nl =
  77             doc.getElementsByTagNameNS(Constants.SignatureSpecNS, "Signature");
  78         if (nl.getLength() == 0) {
  79             throw new Exception("Couldn't find signature Element");
  80         }
  81         Element sigElement = (Element) nl.item(0);
  82         XMLSignature signature = new XMLSignature
  83             (sigElement, file.toURI().toString());
  84         SecretKey sk = signature.createSecretKey("secret".getBytes("ASCII"));
  85         try {
  86             System.out.println
  87                 ("Validation status: " + signature.checkSignatureValue(sk));
  88             if (!pass) {
  89                 System.out.println("FAILED");
  90                 atLeastOneFailed = true;
  91             } else {
  92                 System.out.println("PASSED");
  93             }
  94         } catch (XMLSignatureException xse) {
  95             System.out.println(xse.getMessage());
  96             if (!pass) {
  97                 System.out.println("PASSED");
  98             } else {
  99                 System.out.println("FAILED");
 100                 atLeastOneFailed = true;
 101             }
 102         }
 103     }
 104 
 105     private static void generate_hmac_sha1_40() throws Exception {
 106         System.out.println("Generating ");
 107 
 108         Document doc = dbf.newDocumentBuilder().newDocument();
 109         XMLSignature sig = new XMLSignature
 110             (doc, null, XMLSignature.ALGO_ID_MAC_HMAC_SHA1, 40,
 111              Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
 112         try {
 113             sig.sign(getSecretKey("secret".getBytes("ASCII")));
 114             System.out.println("FAILED");
 115             atLeastOneFailed = true;
 116         } catch (XMLSignatureException xse) {
 117             System.out.println(xse.getMessage());
 118             System.out.println("PASSED");
 119         }
 120     }
 121 
 122     private static SecretKey getSecretKey(final byte[] secret) {
 123         return new SecretKey() {
 124             public String getFormat()   { return "RAW"; }
 125             public byte[] getEncoded()  { return secret; }
 126             public String getAlgorithm(){ return "SECRET"; }
 127         };
 128     }
 129 }