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