001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2013-2015 ForgeRock AS. 015 */ 016 017package org.forgerock.json.jose.jws.handlers; 018 019import org.forgerock.json.jose.exceptions.JwsSigningException; 020import org.forgerock.json.jose.exceptions.JwsVerifyingException; 021import org.forgerock.json.jose.jws.JwsAlgorithm; 022import org.forgerock.json.jose.jws.JwsAlgorithmType; 023import org.forgerock.json.jose.utils.Utils; 024import org.forgerock.util.Reject; 025import org.forgerock.util.SignatureUtil; 026 027import java.security.InvalidKeyException; 028import java.security.Key; 029import java.security.NoSuchAlgorithmException; 030import java.security.PrivateKey; 031import java.security.PublicKey; 032import java.security.Signature; 033import java.security.SignatureException; 034 035/** 036 * An implementation of the SigningHandler which can sign and verify using algorithms from the RSA family. 037 * 038 * @since 2.0.0 039 */ 040public class RSASigningHandler implements SigningHandler { 041 042 private final SignatureUtil signatureUtil; 043 private final Key key; 044 045 /** 046 * Constructs a new RSASigningHandler, with a SignatureUtil instance to delegate the signing and verifying calls to. 047 * 048 * @param key The key used to sign and verify the signature. 049 * @param signatureUtil An instance of the SignatureUtil. 050 */ 051 public RSASigningHandler(Key key, SignatureUtil signatureUtil) { 052 this.key = key; 053 this.signatureUtil = signatureUtil; 054 } 055 056 /** 057 * {@inheritDoc} 058 */ 059 @Override 060 public byte[] sign(JwsAlgorithm algorithm, String data) { 061 validateAlgorithm(algorithm); 062 try { 063 Reject.ifFalse(key instanceof PrivateKey, "RSA requires private key for signing."); 064 return signatureUtil.sign((PrivateKey) key, algorithm.getAlgorithm(), data); 065 } catch (SignatureException e) { 066 if (e.getCause() != null && e.getCause().getClass().isAssignableFrom(NoSuchAlgorithmException.class)) { 067 throw new JwsSigningException("Unsupported Signing Algorithm, " + algorithm.getAlgorithm(), e); 068 } 069 throw new JwsSigningException(e); 070 } 071 } 072 073 /** 074 * {@inheritDoc} 075 */ 076 @Override 077 public byte[] sign(final JwsAlgorithm algorithm, final byte[] data) { 078 validateAlgorithm(algorithm); 079 try { 080 Reject.ifFalse(key instanceof PrivateKey, "RSA requires private key for signing."); 081 Signature signature = Signature.getInstance(algorithm.getAlgorithm()); 082 signature.initSign((PrivateKey) key); 083 signature.update(data); 084 return signature.sign(); 085 } catch (SignatureException | InvalidKeyException e) { 086 throw new JwsSigningException(e); 087 } catch (NoSuchAlgorithmException e) { 088 throw new JwsSigningException("Unsupported Signing Algorithm, " + algorithm.getAlgorithm(), e); 089 } 090 } 091 092 /** 093 * {@inheritDoc} 094 */ 095 @Override 096 public boolean verify(JwsAlgorithm algorithm, byte[] data, byte[] signature) { 097 validateAlgorithm(algorithm); 098 try { 099 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}