View Javadoc
1   /*
2    * The contents of this file are subject to the terms of the Common Development and
3    * Distribution License (the License). You may not use this file except in compliance with the
4    * License.
5    *
6    * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7    * specific language governing permission and limitations under the License.
8    *
9    * When distributing Covered Software, include this CDDL Header Notice in each file and include
10   * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11   * Header, with the fields enclosed by brackets [] replaced by your own identifying
12   * information: "Portions copyright [year] [name of copyright owner]".
13   *
14   * Copyright 2013-2015 ForgeRock AS.
15   */
16  
17  package org.forgerock.json.jose.jws.handlers;
18  
19  import org.forgerock.json.jose.exceptions.JwsSigningException;
20  import org.forgerock.json.jose.exceptions.JwsVerifyingException;
21  import org.forgerock.json.jose.jws.JwsAlgorithm;
22  import org.forgerock.json.jose.jws.JwsAlgorithmType;
23  import org.forgerock.json.jose.utils.Utils;
24  import org.forgerock.util.Reject;
25  import org.forgerock.util.SignatureUtil;
26  
27  import java.security.InvalidKeyException;
28  import java.security.Key;
29  import java.security.NoSuchAlgorithmException;
30  import java.security.PrivateKey;
31  import java.security.PublicKey;
32  import java.security.Signature;
33  import java.security.SignatureException;
34  
35  /**
36   * An implementation of the SigningHandler which can sign and verify using algorithms from the RSA family.
37   *
38   * @since 2.0.0
39   */
40  public class RSASigningHandler implements SigningHandler {
41  
42      private final SignatureUtil signatureUtil;
43      private final Key key;
44  
45      /**
46       * Constructs a new RSASigningHandler, with a SignatureUtil instance to delegate the signing and verifying calls to.
47       *
48       * @param key The key used to sign and verify the signature.
49       * @param signatureUtil An instance of the SignatureUtil.
50       */
51      public RSASigningHandler(Key key, SignatureUtil signatureUtil) {
52          this.key = key;
53          this.signatureUtil = signatureUtil;
54      }
55  
56      /**
57       * {@inheritDoc}
58       */
59      @Override
60      public byte[] sign(JwsAlgorithm algorithm, String data) {
61          validateAlgorithm(algorithm);
62          try {
63              Reject.ifFalse(key instanceof PrivateKey, "RSA requires private key for signing.");
64              return signatureUtil.sign((PrivateKey) key, algorithm.getAlgorithm(), data);
65          } catch (SignatureException e) {
66              if (e.getCause() != null && e.getCause().getClass().isAssignableFrom(NoSuchAlgorithmException.class)) {
67                  throw new JwsSigningException("Unsupported Signing Algorithm, " + algorithm.getAlgorithm(), e);
68              }
69              throw new JwsSigningException(e);
70          }
71      }
72  
73      /**
74       * {@inheritDoc}
75       */
76      @Override
77      public byte[] sign(final JwsAlgorithm algorithm, final byte[] data) {
78          validateAlgorithm(algorithm);
79          try {
80              Reject.ifFalse(key instanceof PrivateKey, "RSA requires private key for signing.");
81              Signature signature = Signature.getInstance(algorithm.getAlgorithm());
82              signature.initSign((PrivateKey) key);
83              signature.update(data);
84              return signature.sign();
85          } catch (SignatureException | InvalidKeyException e) {
86              throw new JwsSigningException(e);
87          } catch (NoSuchAlgorithmException e) {
88              throw new JwsSigningException("Unsupported Signing Algorithm, " + algorithm.getAlgorithm(), e);
89          }
90      }
91  
92      /**
93       * {@inheritDoc}
94       */
95      @Override
96      public boolean verify(JwsAlgorithm algorithm, byte[] data, byte[] signature) {
97          validateAlgorithm(algorithm);
98          try {
99              Reject.ifFalse(key instanceof PublicKey, "RSA requires public key for signature verification.");
100             return signatureUtil.verify((PublicKey) key, algorithm.getAlgorithm(),
101                     new String(data, Utils.CHARSET), signature);
102         } catch (SignatureException e) {
103             if (e.getCause() != null && e.getCause().getClass().isAssignableFrom(NoSuchAlgorithmException.class)) {
104                 throw new JwsVerifyingException("Unsupported Signing Algorithm, " + algorithm.getAlgorithm(), e);
105             }
106             throw new JwsVerifyingException(e);
107         }
108     }
109 
110     private void validateAlgorithm(JwsAlgorithm algorithm) {
111         Reject.ifNull(algorithm, "Algorithm must not be null.");
112         Reject.ifTrue(algorithm.getAlgorithmType() != JwsAlgorithmType.RSA, "Not an RSA algorithm.");
113     }
114 }