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 * @modules java.xml.crypto/com.sun.org.apache.xml.internal.security
30 *          java.xml.crypto/com.sun.org.apache.xml.internal.security.c14n
31 *          java.xml.crypto/com.sun.org.apache.xml.internal.security.signature
32 *          java.xml.crypto/com.sun.org.apache.xml.internal.security.utils
33 * @compile -XDignore.symbol.file TruncateHMAC.java
34 * @run main TruncateHMAC
35 */
36
37import java.io.File;
38import javax.crypto.SecretKey;
39import javax.xml.parsers.DocumentBuilderFactory;
40import org.w3c.dom.Document;
41import org.w3c.dom.Element;
42import org.w3c.dom.NodeList;
43
44import com.sun.org.apache.xml.internal.security.Init;
45import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer;
46import com.sun.org.apache.xml.internal.security.signature.XMLSignature;
47import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException;
48import com.sun.org.apache.xml.internal.security.utils.Constants;
49
50
51public class TruncateHMAC {
52
53    private final static String DIR = System.getProperty("test.src", ".");
54    private static DocumentBuilderFactory dbf = null;
55    private static boolean atLeastOneFailed = false;
56
57    public static void main(String[] args) throws Exception {
58
59        Init.init();
60        dbf = DocumentBuilderFactory.newInstance();
61        dbf.setNamespaceAware(true);
62        dbf.setValidating(false);
63        validate("signature-enveloping-hmac-sha1-trunclen-0-attack.xml", false);
64        validate("signature-enveloping-hmac-sha1-trunclen-8-attack.xml", false);
65        // this one should pass
66        validate("signature-enveloping-hmac-sha1.xml", true);
67        generate_hmac_sha1_40();
68
69        if (atLeastOneFailed) {
70            throw new Exception
71                ("At least one signature did not validate as expected");
72        }
73    }
74
75    private static void validate(String data, boolean pass) throws Exception {
76        System.out.println("Validating " + data);
77        File file = new File(DIR, data);
78
79        Document doc = dbf.newDocumentBuilder().parse(file);
80        NodeList nl =
81            doc.getElementsByTagNameNS(Constants.SignatureSpecNS, "Signature");
82        if (nl.getLength() == 0) {
83            throw new Exception("Couldn't find signature Element");
84        }
85        Element sigElement = (Element) nl.item(0);
86        XMLSignature signature = new XMLSignature
87            (sigElement, file.toURI().toString());
88        SecretKey sk = signature.createSecretKey("secret".getBytes("ASCII"));
89        try {
90            System.out.println
91                ("Validation status: " + signature.checkSignatureValue(sk));
92            if (!pass) {
93                System.out.println("FAILED");
94                atLeastOneFailed = true;
95            } else {
96                System.out.println("PASSED");
97            }
98        } catch (XMLSignatureException xse) {
99            System.out.println(xse.getMessage());
100            if (!pass) {
101                System.out.println("PASSED");
102            } else {
103                System.out.println("FAILED");
104                atLeastOneFailed = true;
105            }
106        }
107    }
108
109    private static void generate_hmac_sha1_40() throws Exception {
110        System.out.println("Generating ");
111
112        Document doc = dbf.newDocumentBuilder().newDocument();
113        XMLSignature sig = new XMLSignature
114            (doc, null, XMLSignature.ALGO_ID_MAC_HMAC_SHA1, 40,
115             Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
116        try {
117            sig.sign(getSecretKey("secret".getBytes("ASCII")));
118            System.out.println("FAILED");
119            atLeastOneFailed = true;
120        } catch (XMLSignatureException xse) {
121            System.out.println(xse.getMessage());
122            System.out.println("PASSED");
123        }
124    }
125
126    private static SecretKey getSecretKey(final byte[] secret) {
127        return new SecretKey() {
128            public String getFormat()   { return "RAW"; }
129            public byte[] getEncoded()  { return secret; }
130            public String getAlgorithm(){ return "SECRET"; }
131        };
132    }
133}
134