1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /**
   6  * Licensed to the Apache Software Foundation (ASF) under one
   7  * or more contributor license agreements. See the NOTICE file
   8  * distributed with this work for additional information
   9  * regarding copyright ownership. The ASF licenses this file
  10  * to you under the Apache License, Version 2.0 (the
  11  * "License"); you may not use this file except in compliance
  12  * with the License. You may obtain a copy of the License at
  13  *
  14  * http://www.apache.org/licenses/LICENSE-2.0
  15  *
  16  * Unless required by applicable law or agreed to in writing,
  17  * software distributed under the License is distributed on an
  18  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  19  * KIND, either express or implied. See the License for the
  20  * specific language governing permissions and limitations
  21  * under the License.
  22  */
  23 /*
  24  * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
  25  */
  26 /*
  27  * $Id: DOMSignatureMethod.java 1333415 2012-05-03 12:03:51Z coheigea $
  28  */
  29 package org.jcp.xml.dsig.internal.dom;
  30 
  31 import javax.xml.crypto.*;
  32 import javax.xml.crypto.dsig.*;
  33 import javax.xml.crypto.dsig.spec.SignatureMethodParameterSpec;
  34 
  35 import java.io.IOException;
  36 import java.security.*;
  37 import java.security.spec.AlgorithmParameterSpec;
  38 import org.w3c.dom.Element;
  39 
  40 import com.sun.org.apache.xml.internal.security.algorithms.implementations.SignatureECDSA;
  41 import org.jcp.xml.dsig.internal.SignerOutputStream;
  42 
  43 /**
  44  * DOM-based abstract implementation of SignatureMethod.
  45  *
  46  * @author Sean Mullan
  47  */
  48 public abstract class DOMSignatureMethod extends AbstractDOMSignatureMethod {
  49 
  50     private static java.util.logging.Logger log =
  51         java.util.logging.Logger.getLogger("org.jcp.xml.dsig.internal.dom");
  52 
  53     private SignatureMethodParameterSpec params;
  54     private Signature signature;
  55     
  56     // see RFC 4051 for these algorithm definitions
  57     static final String RSA_SHA256 =
  58         "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
  59     static final String RSA_SHA384 =
  60         "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384";
  61     static final String RSA_SHA512 =
  62         "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512";
  63     static final String ECDSA_SHA1 =
  64         "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1";
  65     static final String ECDSA_SHA256 =
  66         "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256";
  67     static final String ECDSA_SHA384 =
  68         "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384";
  69     static final String ECDSA_SHA512 =
  70         "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512";
  71 
  72     /**
  73      * Creates a <code>DOMSignatureMethod</code>.
  74      *
  75      * @param params the algorithm-specific params (may be <code>null</code>)
  76      * @throws InvalidAlgorithmParameterException if the parameters are not
  77      *    appropriate for this signature method
  78      */
  79     DOMSignatureMethod(AlgorithmParameterSpec params) 
  80         throws InvalidAlgorithmParameterException
  81     {
  82         if (params != null && 
  83             !(params instanceof SignatureMethodParameterSpec)) {
  84             throw new InvalidAlgorithmParameterException
  85                 ("params must be of type SignatureMethodParameterSpec");
  86         }
  87         checkParams((SignatureMethodParameterSpec)params);
  88         this.params = (SignatureMethodParameterSpec)params;
  89     }
  90 
  91     /**
  92      * Creates a <code>DOMSignatureMethod</code> from an element. This ctor
  93      * invokes the {@link #unmarshalParams unmarshalParams} method to
  94      * unmarshal any algorithm-specific input parameters.
  95      *
  96      * @param smElem a SignatureMethod element
  97      */
  98     DOMSignatureMethod(Element smElem) throws MarshalException {
  99         Element paramsElem = DOMUtils.getFirstChildElement(smElem);
 100         if (paramsElem != null) {
 101             params = unmarshalParams(paramsElem);
 102         }
 103         try {
 104             checkParams(params);
 105         } catch (InvalidAlgorithmParameterException iape) {
 106             throw new MarshalException(iape);
 107         }
 108     }
 109 
 110     static SignatureMethod unmarshal(Element smElem) throws MarshalException {
 111         String alg = DOMUtils.getAttributeValue(smElem, "Algorithm");
 112         if (alg.equals(SignatureMethod.RSA_SHA1)) {
 113             return new SHA1withRSA(smElem);
 114         } else if (alg.equals(RSA_SHA256)) {
 115             return new SHA256withRSA(smElem);
 116         } else if (alg.equals(RSA_SHA384)) {
 117             return new SHA384withRSA(smElem);
 118         } else if (alg.equals(RSA_SHA512)) {
 119             return new SHA512withRSA(smElem);
 120         } else if (alg.equals(SignatureMethod.DSA_SHA1)) {
 121             return new SHA1withDSA(smElem);
 122         } else if (alg.equals(ECDSA_SHA1)) {
 123             return new SHA1withECDSA(smElem);
 124         } else if (alg.equals(ECDSA_SHA256)) {
 125             return new SHA256withECDSA(smElem);
 126         } else if (alg.equals(ECDSA_SHA384)) {
 127             return new SHA384withECDSA(smElem);
 128         } else if (alg.equals(ECDSA_SHA512)) {
 129             return new SHA512withECDSA(smElem);
 130         } else if (alg.equals(SignatureMethod.HMAC_SHA1)) {
 131             return new DOMHMACSignatureMethod.SHA1(smElem);
 132         } else if (alg.equals(DOMHMACSignatureMethod.HMAC_SHA256)) {
 133             return new DOMHMACSignatureMethod.SHA256(smElem);
 134         } else if (alg.equals(DOMHMACSignatureMethod.HMAC_SHA384)) {
 135             return new DOMHMACSignatureMethod.SHA384(smElem);
 136         } else if (alg.equals(DOMHMACSignatureMethod.HMAC_SHA512)) {
 137             return new DOMHMACSignatureMethod.SHA512(smElem);
 138         } else {
 139             throw new MarshalException
 140                 ("unsupported SignatureMethod algorithm: " + alg);
 141         }
 142     }
 143 
 144     public final AlgorithmParameterSpec getParameterSpec() {
 145         return params;
 146     }
 147 
 148     boolean verify(Key key, SignedInfo si, byte[] sig,
 149                    XMLValidateContext context)
 150         throws InvalidKeyException, SignatureException, XMLSignatureException
 151     {
 152         if (key == null || si == null || sig == null) {
 153             throw new NullPointerException();
 154         }
 155 
 156         if (!(key instanceof PublicKey)) {
 157             throw new InvalidKeyException("key must be PublicKey");
 158         }
 159         if (signature == null) {
 160             try {
 161                 Provider p = (Provider)context.getProperty
 162                     ("org.jcp.xml.dsig.internal.dom.SignatureProvider");
 163                 signature = (p == null)
 164                     ? Signature.getInstance(getJCAAlgorithm()) 
 165                     : Signature.getInstance(getJCAAlgorithm(), p);
 166             } catch (NoSuchAlgorithmException nsae) {
 167                 throw new XMLSignatureException(nsae);
 168             }
 169         }
 170         signature.initVerify((PublicKey)key);
 171         if (log.isLoggable(java.util.logging.Level.FINE)) {
 172             log.log(java.util.logging.Level.FINE, "Signature provider:" + signature.getProvider());
 173             log.log(java.util.logging.Level.FINE, "verifying with key: " + key);
 174         }
 175         ((DOMSignedInfo)si).canonicalize(context,
 176                                          new SignerOutputStream(signature));
 177 
 178         try {
 179             Type type = getAlgorithmType();
 180             if (type == Type.DSA) {
 181                 return signature.verify(convertXMLDSIGtoASN1(sig));
 182             } else if (type == Type.ECDSA) {
 183                 return signature.verify(SignatureECDSA.convertXMLDSIGtoASN1(sig));
 184             } else {
 185                 return signature.verify(sig);
 186             }
 187         } catch (IOException ioe) {
 188             throw new XMLSignatureException(ioe);
 189         }
 190     }
 191 
 192     byte[] sign(Key key, SignedInfo si, XMLSignContext context)
 193         throws InvalidKeyException, XMLSignatureException
 194     {
 195         if (key == null || si == null) {
 196             throw new NullPointerException();
 197         }
 198 
 199         if (!(key instanceof PrivateKey)) {
 200             throw new InvalidKeyException("key must be PrivateKey");
 201         }
 202         if (signature == null) {
 203             try {
 204                 Provider p = (Provider)context.getProperty
 205                     ("org.jcp.xml.dsig.internal.dom.SignatureProvider");
 206                 signature = (p == null)
 207                     ? Signature.getInstance(getJCAAlgorithm()) 
 208                     : Signature.getInstance(getJCAAlgorithm(), p);
 209             } catch (NoSuchAlgorithmException nsae) {
 210                 throw new XMLSignatureException(nsae);
 211             }
 212         }
 213         signature.initSign((PrivateKey)key);
 214         if (log.isLoggable(java.util.logging.Level.FINE)) {
 215             log.log(java.util.logging.Level.FINE, "Signature provider:" + signature.getProvider());
 216             log.log(java.util.logging.Level.FINE, "Signing with key: " + key);
 217         }
 218 
 219         ((DOMSignedInfo)si).canonicalize(context,
 220                                          new SignerOutputStream(signature));
 221 
 222         try {
 223             Type type = getAlgorithmType();
 224             if (type == Type.DSA) {
 225                 return convertASN1toXMLDSIG(signature.sign());
 226             } else if (type == Type.ECDSA) {
 227                 return SignatureECDSA.convertASN1toXMLDSIG(signature.sign());
 228             } else {
 229                 return signature.sign();
 230             }
 231         } catch (SignatureException se) {
 232             throw new XMLSignatureException(se);
 233         } catch (IOException ioe) {
 234             throw new XMLSignatureException(ioe);
 235         }
 236     }
 237 
 238     /**
 239      * Converts an ASN.1 DSA value to a XML Signature DSA Value.
 240      *
 241      * The JAVA JCE DSA Signature algorithm creates ASN.1 encoded (r,s) value
 242      * pairs; the XML Signature requires the core BigInteger values.
 243      *
 244      * @param asn1Bytes
 245      *
 246      * @throws IOException
 247      * @see <A HREF="http://www.w3.org/TR/xmldsig-core/#dsa-sha1">6.4.1 DSA</A>
 248      */
 249     private static byte[] convertASN1toXMLDSIG(byte asn1Bytes[])
 250         throws IOException
 251     {
 252         byte rLength = asn1Bytes[3];
 253         int i;
 254 
 255         for (i = rLength; (i > 0) && (asn1Bytes[(4 + rLength) - i] == 0); i--);
 256 
 257         byte sLength = asn1Bytes[5 + rLength];
 258         int j;
 259 
 260         for (j = sLength;
 261             (j > 0) && (asn1Bytes[(6 + rLength + sLength) - j] == 0); j--);
 262 
 263         if ((asn1Bytes[0] != 48) || (asn1Bytes[1] != asn1Bytes.length - 2)
 264             || (asn1Bytes[2] != 2) || (i > 20)
 265             || (asn1Bytes[4 + rLength] != 2) || (j > 20)) {
 266             throw new IOException("Invalid ASN.1 format of DSA signature");
 267         } else {
 268             byte xmldsigBytes[] = new byte[40];
 269 
 270             System.arraycopy(asn1Bytes, (4+rLength)-i, xmldsigBytes, 20-i, i);
 271             System.arraycopy(asn1Bytes, (6+rLength+sLength)-j, xmldsigBytes,
 272                              40 - j, j);
 273 
 274             return xmldsigBytes;
 275         }
 276     }
 277 
 278     /**
 279      * Converts a XML Signature DSA Value to an ASN.1 DSA value.
 280      *
 281      * The JAVA JCE DSA Signature algorithm creates ASN.1 encoded (r,s) value
 282      * pairs; the XML Signature requires the core BigInteger values.
 283      *
 284      * @param xmldsigBytes
 285      *
 286      * @throws IOException
 287      * @see <A HREF="http://www.w3.org/TR/xmldsig-core/#dsa-sha1">6.4.1 DSA</A>
 288      */
 289     private static byte[] convertXMLDSIGtoASN1(byte xmldsigBytes[])
 290         throws IOException
 291     {
 292         if (xmldsigBytes.length != 40) {
 293             throw new IOException("Invalid XMLDSIG format of DSA signature");
 294         }
 295 
 296         int i;
 297 
 298         for (i = 20; (i > 0) && (xmldsigBytes[20 - i] == 0); i--);
 299 
 300         int j = i;
 301 
 302         if (xmldsigBytes[20 - i] < 0) {
 303             j += 1;
 304         }
 305 
 306         int k;
 307 
 308         for (k = 20; (k > 0) && (xmldsigBytes[40 - k] == 0); k--);
 309 
 310         int l = k;
 311 
 312         if (xmldsigBytes[40 - k] < 0) {
 313             l += 1;
 314         }
 315 
 316         byte asn1Bytes[] = new byte[6 + j + l];
 317 
 318         asn1Bytes[0] = 48;
 319         asn1Bytes[1] = (byte)(4 + j + l);
 320         asn1Bytes[2] = 2;
 321         asn1Bytes[3] = (byte)j;
 322 
 323         System.arraycopy(xmldsigBytes, 20 - i, asn1Bytes, (4 + j) - i, i);
 324 
 325         asn1Bytes[4 + j] = 2;
 326         asn1Bytes[5 + j] = (byte) l;
 327 
 328         System.arraycopy(xmldsigBytes, 40 - k, asn1Bytes, (6 + j + l) - k, k);
 329 
 330         return asn1Bytes;
 331     }
 332 
 333     static final class SHA1withRSA extends DOMSignatureMethod {
 334         SHA1withRSA(AlgorithmParameterSpec params)
 335             throws InvalidAlgorithmParameterException {
 336             super(params);
 337         }
 338         SHA1withRSA(Element dmElem) throws MarshalException {
 339             super(dmElem);
 340         }
 341         public String getAlgorithm() {
 342             return SignatureMethod.RSA_SHA1;
 343         }
 344         String getJCAAlgorithm() {
 345             return "SHA1withRSA";
 346         }
 347         Type getAlgorithmType() {
 348             return Type.RSA;
 349         }
 350     }
 351 
 352     static final class SHA256withRSA extends DOMSignatureMethod {
 353         SHA256withRSA(AlgorithmParameterSpec params)
 354             throws InvalidAlgorithmParameterException {
 355             super(params);
 356         }
 357         SHA256withRSA(Element dmElem) throws MarshalException {
 358             super(dmElem);
 359         }
 360         public String getAlgorithm() {
 361             return RSA_SHA256;
 362         }
 363         String getJCAAlgorithm() {
 364             return "SHA256withRSA";
 365         }
 366         Type getAlgorithmType() {
 367             return Type.RSA;
 368         }
 369     }
 370 
 371     static final class SHA384withRSA extends DOMSignatureMethod {
 372         SHA384withRSA(AlgorithmParameterSpec params)
 373             throws InvalidAlgorithmParameterException {
 374             super(params);
 375         }
 376         SHA384withRSA(Element dmElem) throws MarshalException {
 377             super(dmElem);
 378         }
 379         public String getAlgorithm() {
 380             return RSA_SHA384;
 381         }
 382         String getJCAAlgorithm() {
 383             return "SHA384withRSA";
 384         }
 385         Type getAlgorithmType() {
 386             return Type.RSA;
 387         }
 388     }
 389 
 390     static final class SHA512withRSA extends DOMSignatureMethod {
 391         SHA512withRSA(AlgorithmParameterSpec params)
 392             throws InvalidAlgorithmParameterException {
 393             super(params);
 394         }
 395         SHA512withRSA(Element dmElem) throws MarshalException {
 396             super(dmElem);
 397         }
 398         public String getAlgorithm() {
 399             return RSA_SHA512;
 400         }
 401         String getJCAAlgorithm() {
 402             return "SHA512withRSA";
 403         }
 404         Type getAlgorithmType() {
 405             return Type.RSA;
 406         }
 407     }
 408 
 409     static final class SHA1withDSA extends DOMSignatureMethod {
 410         SHA1withDSA(AlgorithmParameterSpec params)
 411             throws InvalidAlgorithmParameterException {
 412             super(params);
 413         }
 414         SHA1withDSA(Element dmElem) throws MarshalException {
 415             super(dmElem);
 416         }
 417         public String getAlgorithm() {
 418             return SignatureMethod.DSA_SHA1;
 419         }
 420         String getJCAAlgorithm() {
 421             return "SHA1withDSA";
 422         }
 423         Type getAlgorithmType() {
 424             return Type.DSA;
 425         }
 426     }
 427 
 428     static final class SHA1withECDSA extends DOMSignatureMethod {
 429         SHA1withECDSA(AlgorithmParameterSpec params)
 430             throws InvalidAlgorithmParameterException {
 431             super(params);
 432         }
 433         SHA1withECDSA(Element dmElem) throws MarshalException {
 434             super(dmElem);
 435         }
 436         public String getAlgorithm() {
 437             return ECDSA_SHA1;
 438         }
 439         String getJCAAlgorithm() {
 440             return "SHA1withECDSA";
 441         }
 442         Type getAlgorithmType() {
 443             return Type.ECDSA;
 444         }
 445     }
 446 
 447     static final class SHA256withECDSA extends DOMSignatureMethod {
 448         SHA256withECDSA(AlgorithmParameterSpec params)
 449             throws InvalidAlgorithmParameterException {
 450             super(params);
 451         }
 452         SHA256withECDSA(Element dmElem) throws MarshalException {
 453             super(dmElem);
 454         }
 455         public String getAlgorithm() {
 456             return ECDSA_SHA256;
 457         }
 458         String getJCAAlgorithm() {
 459             return "SHA256withECDSA";
 460         }
 461         Type getAlgorithmType() {
 462             return Type.ECDSA;
 463         }
 464     }
 465 
 466     static final class SHA384withECDSA extends DOMSignatureMethod {
 467         SHA384withECDSA(AlgorithmParameterSpec params)
 468             throws InvalidAlgorithmParameterException {
 469             super(params);
 470         }
 471         SHA384withECDSA(Element dmElem) throws MarshalException {
 472             super(dmElem);
 473         }
 474         public String getAlgorithm() {
 475             return ECDSA_SHA384;
 476         }
 477         String getJCAAlgorithm() {
 478             return "SHA384withECDSA";
 479         }
 480         Type getAlgorithmType() {
 481             return Type.ECDSA;
 482         }
 483     }
 484 
 485     static final class SHA512withECDSA extends DOMSignatureMethod {
 486         SHA512withECDSA(AlgorithmParameterSpec params)
 487             throws InvalidAlgorithmParameterException {
 488             super(params);
 489         }
 490         SHA512withECDSA(Element dmElem) throws MarshalException {
 491             super(dmElem);
 492         }
 493         public String getAlgorithm() {
 494             return ECDSA_SHA512;
 495         }
 496         String getJCAAlgorithm() {
 497             return "SHA512withECDSA";
 498         }
 499         Type getAlgorithmType() {
 500             return Type.ECDSA;
 501         }
 502     }
 503 }