001package com.nimbusds.jose.crypto;
002
003
004import java.security.InvalidKeyException;
005import java.security.Signature;
006import java.security.SignatureException;
007import java.security.interfaces.RSAPrivateKey;
008
009import net.jcip.annotations.ThreadSafe;
010
011import com.nimbusds.jose.JOSEException;
012import com.nimbusds.jose.JWSSigner;
013import com.nimbusds.jose.JWSHeader;
014import com.nimbusds.jose.jwk.RSAKey;
015import com.nimbusds.jose.util.Base64URL;
016
017
018
019/**
020 * RSA Signature-Scheme-with-Appendix (RSASSA) signer of 
021 * {@link com.nimbusds.jose.JWSObject JWS objects}. This class is thread-safe.
022 *
023 * <p>Supports the following algorithms:
024 *
025 * <ul>
026 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#RS256}
027 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#RS384}
028 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#RS512}
029 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#PS256}
030 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#PS384}
031 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#PS512}
032 * </ul>
033 * 
034 * @author Vladimir Dzhuvinov
035 * @version 2015-06-02
036 */
037@ThreadSafe
038public class RSASSASigner extends RSASSAProvider implements JWSSigner {
039
040
041        /**
042         * The private RSA key.
043         */
044        private final RSAPrivateKey privateKey;
045
046
047        /**
048         * Creates a new RSA Signature-Scheme-with-Appendix (RSASSA) signer.
049         *
050         * @param privateKey The private RSA key. Must not be {@code null}.
051         */
052        public RSASSASigner(final RSAPrivateKey privateKey) {
053
054                if (privateKey == null) {
055                        throw new IllegalArgumentException("The private RSA key must not be null");
056                }
057
058                this.privateKey = privateKey;
059        }
060
061
062        /**
063         * Creates a new RSA Signature-Scheme-with-Appendix (RSASSA) signer.
064         *
065         * @param rsaJWK The RSA JSON Web Key (JWK). Must contain a private
066         *               part. Must not be {@code null}.
067         *
068         * @throws JOSEException If the RSA JWK doesn't contain a private part
069         *                       or its extraction failed.
070         */
071        public RSASSASigner(final RSAKey rsaJWK)
072                throws JOSEException {
073
074                if (! rsaJWK.isPrivate()) {
075                        throw new JOSEException("The RSA JWK doesn't contain a private part");
076                }
077
078                privateKey = rsaJWK.toRSAPrivateKey();
079        }
080
081
082        /**
083         * Gets the private RSA key.
084         *
085         * @return The private RSA key.
086         */
087        public RSAPrivateKey getPrivateKey() {
088
089                return privateKey;
090        }
091
092
093        @Override
094        public Base64URL sign(final JWSHeader header, final byte[] signingInput)
095                throws JOSEException {
096
097                Signature signer = RSASSA.getSignerAndVerifier(header.getAlgorithm(), getJCAContext().getProvider());
098
099                try {
100                        signer.initSign(privateKey);
101                        signer.update(signingInput);
102                        return Base64URL.encode(signer.sign());
103
104                } catch (InvalidKeyException e) {
105                        throw new JOSEException("Invalid private RSA key: " + e.getMessage(), e);
106
107                } catch (SignatureException e) {
108                        throw new JOSEException("RSA signature exception: " + e.getMessage(), e);
109                }
110        }
111}