001/* 002 * nimbus-jose-jwt 003 * 004 * Copyright 2012-2016, Connect2id Ltd. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.jose.crypto; 019 020 021import java.security.InvalidKeyException; 022import java.security.PrivateKey; 023import java.security.Signature; 024import java.security.SignatureException; 025 026import static com.nimbusds.jose.jwk.gen.RSAKeyGenerator.MIN_KEY_SIZE_BITS; 027 028import com.nimbusds.jose.JOSEException; 029import com.nimbusds.jose.JWSHeader; 030import com.nimbusds.jose.JWSSigner; 031import com.nimbusds.jose.crypto.impl.RSAKeyUtils; 032import com.nimbusds.jose.crypto.impl.RSASSA; 033import com.nimbusds.jose.crypto.impl.RSASSAProvider; 034import com.nimbusds.jose.jwk.RSAKey; 035import com.nimbusds.jose.util.Base64URL; 036import net.jcip.annotations.ThreadSafe; 037 038 039 040/** 041 * RSA Signature-Scheme-with-Appendix (RSASSA) signer of 042 * {@link com.nimbusds.jose.JWSObject JWS objects}. Expects a private RSA key. 043 * 044 * <p>See RFC 7518, sections 045 * <a href="https://tools.ietf.org/html/rfc7518#section-3.3">3.3</a> and 046 * <a href="https://tools.ietf.org/html/rfc7518#section-3.5">3.5</a> for more 047 * information. 048 * 049 * <p>This class is thread-safe. 050 * 051 * <p>Supports the following algorithms: 052 * 053 * <ul> 054 * <li>{@link com.nimbusds.jose.JWSAlgorithm#RS256} 055 * <li>{@link com.nimbusds.jose.JWSAlgorithm#RS384} 056 * <li>{@link com.nimbusds.jose.JWSAlgorithm#RS512} 057 * <li>{@link com.nimbusds.jose.JWSAlgorithm#PS256} 058 * <li>{@link com.nimbusds.jose.JWSAlgorithm#PS384} 059 * <li>{@link com.nimbusds.jose.JWSAlgorithm#PS512} 060 * </ul> 061 * 062 * <p>Supports the 063 * {@link com.nimbusds.jose.crypto.bc.BouncyCastleFIPSProviderSingleton 064 * BouncyCastle FIPS provider} for the PSxxx family of JWS algorithms. 065 * 066 * @author Vladimir Dzhuvinov 067 * @author Omer Levi Hevroni 068 * @version 2018-10-11 069 */ 070@ThreadSafe 071public class RSASSASigner extends RSASSAProvider implements JWSSigner { 072 073 074 /** 075 * The private RSA key. Represented by generic private key interface to 076 * support key stores that prevent exposure of the private key 077 * parameters via the {@link java.security.interfaces.RSAPrivateKey} 078 * API. 079 * 080 * See https://bitbucket.org/connect2id/nimbus-jose-jwt/issues/169 081 */ 082 private final PrivateKey privateKey; 083 084 085 /** 086 * Creates a new RSA Signature-Scheme-with-Appendix (RSASSA) signer. 087 * This constructor can also accept a private RSA key located in a 088 * PKCS#11 store that doesn't expose the private key parameters (such 089 * as a smart card or HSM). 090 * 091 * @param privateKey The private RSA key. Its algorithm must be "RSA" 092 * and its length at least 2048 bits. Note that the 093 * length of an RSA key in a PKCS#11 store cannot be 094 * checked. Must not be {@code null}. 095 */ 096 public RSASSASigner(final PrivateKey privateKey) { 097 098 this(privateKey, false); 099 } 100 101 102 /** 103 * Creates a new RSA Signature-Scheme-with-Appendix (RSASSA) signer. 104 * This constructor can also accept a private RSA key located in a 105 * PKCS#11 store that doesn't expose the private key parameters (such 106 * as a smart card or HSM). 107 * 108 * @param privateKey The private RSA key. Its algorithm must be 109 * "RSA" and its length at least 2048 bits. Note 110 * that the length of an RSA key in a PKCS#11 store 111 * cannot be checked. Must not be {@code null}. 112 * @param allowWeakKey {@code true} to allow an RSA key shorter than 113 * 2048 bits. 114 */ 115 public RSASSASigner(final PrivateKey privateKey, final boolean allowWeakKey) { 116 117 if (! "RSA".equalsIgnoreCase(privateKey.getAlgorithm())) { 118 throw new IllegalArgumentException("The private key algorithm must be RSA"); 119 } 120 121 if (! allowWeakKey) { 122 123 int keyBitLength = RSAKeyUtils.keyBitLength(privateKey); 124 125 if (keyBitLength > 0 && keyBitLength < MIN_KEY_SIZE_BITS) { 126 throw new IllegalArgumentException("The RSA key size must be at least " + MIN_KEY_SIZE_BITS + " bits"); 127 } 128 } 129 130 this.privateKey = privateKey; 131 } 132 133 134 /** 135 * Creates a new RSA Signature-Scheme-with-Appendix (RSASSA) signer. 136 * 137 * @param rsaJWK The RSA JSON Web Key (JWK). Must contain or reference 138 * a private part. Its length must be at least 2048 bits. 139 * Note that the length of an RSA key in a PKCS#11 store 140 * cannot be checked. Must not be {@code null}. 141 * 142 * @throws JOSEException If the RSA JWK doesn't contain a private part 143 * or its extraction failed. 144 */ 145 public RSASSASigner(final RSAKey rsaJWK) 146 throws JOSEException { 147 148 this(rsaJWK, false); 149 } 150 151 152 /** 153 * Creates a new RSA Signature-Scheme-with-Appendix (RSASSA) signer. 154 * 155 * @param rsaJWK The RSA JSON Web Key (JWK). Must contain or 156 * reference a private part. Its length must be at 157 * least 2048 bits. Note that the length of an RSA 158 * key in a PKCS#11 store cannot be checked. Must 159 * not be {@code null}. 160 * @param allowWeakKey {@code true} to allow an RSA key shorter than 161 * 2048 bits. 162 * 163 * @throws JOSEException If the RSA JWK doesn't contain a private part 164 * or its extraction failed. 165 */ 166 public RSASSASigner(final RSAKey rsaJWK, final boolean allowWeakKey) 167 throws JOSEException { 168 169 this(RSAKeyUtils.toRSAPrivateKey(rsaJWK), allowWeakKey); 170 } 171 172 173 /** 174 * Gets the private RSA key. 175 * 176 * @return The private RSA key. Casting to 177 * {@link java.security.interfaces.RSAPrivateKey} may not be 178 * possible if the key is located in a PKCS#11 store that 179 * doesn't expose the private key parameters. 180 */ 181 public PrivateKey getPrivateKey() { 182 183 return privateKey; 184 } 185 186 187 @Override 188 public Base64URL sign(final JWSHeader header, final byte[] signingInput) 189 throws JOSEException { 190 191 Signature signer = RSASSA.getSignerAndVerifier(header.getAlgorithm(), getJCAContext().getProvider()); 192 193 try { 194 signer.initSign(privateKey); 195 signer.update(signingInput); 196 return Base64URL.encode(signer.sign()); 197 198 } catch (InvalidKeyException e) { 199 throw new JOSEException("Invalid private RSA key: " + e.getMessage(), e); 200 201 } catch (SignatureException e) { 202 throw new JOSEException("RSA signature exception: " + e.getMessage(), e); 203 } 204 } 205}