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. Its algorithm must be "RSA". 056 * Must not be {@code null}. 057 */ 058 public RSASSASigner(final PrivateKey privateKey) { 059 060 if (! privateKey.getAlgorithm().equalsIgnoreCase("RSA")) { 061 throw new IllegalArgumentException("The private key algorithm must be RSA"); 062 } 063 064 this.privateKey = privateKey; 065 } 066 067 068 /** 069 * Creates a new RSA Signature-Scheme-with-Appendix (RSASSA) signer. 070 * 071 * @param rsaJWK The RSA JSON Web Key (JWK). Must contain a private 072 * part. Must not be {@code null}. 073 * 074 * @throws JOSEException If the RSA JWK doesn't contain a private part 075 * or its extraction failed. 076 */ 077 public RSASSASigner(final RSAKey rsaJWK) 078 throws JOSEException { 079 080 if (! rsaJWK.isPrivate()) { 081 throw new JOSEException("The RSA JWK doesn't contain a private part"); 082 } 083 084 privateKey = rsaJWK.toRSAPrivateKey(); 085 } 086 087 088 /** 089 * Gets the private RSA key. 090 * 091 * @return The private RSA key. Casting to 092 * {@link java.security.interfaces.RSAPrivateKey} may not be 093 * possible if the key is backed by a key store that doesn't 094 * expose the private key parameters. 095 */ 096 public PrivateKey getPrivateKey() { 097 098 return privateKey; 099 } 100 101 102 @Override 103 public Base64URL sign(final JWSHeader header, final byte[] signingInput) 104 throws JOSEException { 105 106 Signature signer = RSASSA.getSignerAndVerifier(header.getAlgorithm(), getJCAContext().getProvider()); 107 108 try { 109 signer.initSign(privateKey); 110 signer.update(signingInput); 111 return Base64URL.encode(signer.sign()); 112 113 } catch (InvalidKeyException e) { 114 throw new JOSEException("Invalid private RSA key: " + e.getMessage(), e); 115 116 } catch (SignatureException e) { 117 throw new JOSEException("RSA signature exception: " + e.getMessage(), e); 118 } 119 } 120}