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