001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2016, Connect2id Ltd and contributors. 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.oauth2.sdk.assertions.jwt; 019 020 021import java.security.PrivateKey; 022import java.security.Provider; 023import java.security.interfaces.ECPrivateKey; 024import java.security.interfaces.RSAPrivateKey; 025import java.util.Collections; 026import java.util.HashSet; 027import java.util.List; 028import java.util.Set; 029 030import com.nimbusds.jose.JOSEException; 031import com.nimbusds.jose.JWSAlgorithm; 032import com.nimbusds.jose.JWSHeader; 033import com.nimbusds.jose.JWSSigner; 034import com.nimbusds.jose.crypto.ECDSASigner; 035import com.nimbusds.jose.crypto.MACSigner; 036import com.nimbusds.jose.crypto.RSASSASigner; 037import com.nimbusds.jose.jwk.Curve; 038import com.nimbusds.jose.util.Base64; 039import com.nimbusds.jose.util.Base64URL; 040import com.nimbusds.jwt.SignedJWT; 041import com.nimbusds.oauth2.sdk.auth.Secret; 042 043 044/** 045 * Static JWT bearer assertion factory. 046 * 047 * <p>Related specifications: 048 * 049 * <ul> 050 * <li>Assertion Framework for OAuth 2.0 Client Authentication and 051 * Authorization Grants (RFC 7521). 052 * <li>JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and 053 * Authorization Grants (RFC 7523). 054 * </ul> 055 */ 056public class JWTAssertionFactory { 057 058 059 /** 060 * Returns the supported signature JSON Web Algorithms (JWAs). 061 * 062 * @return The supported JSON Web Algorithms (JWAs). 063 */ 064 public static Set<JWSAlgorithm> supportedJWAs() { 065 066 Set<JWSAlgorithm> supported = new HashSet<>(); 067 supported.addAll(JWSAlgorithm.Family.HMAC_SHA); 068 supported.addAll(JWSAlgorithm.Family.RSA); 069 supported.addAll(JWSAlgorithm.Family.EC); 070 return Collections.unmodifiableSet(supported); 071 } 072 073 074 /** 075 * Creates a new HMAC-protected JWT bearer assertion. 076 * 077 * @param details The JWT bearer assertion details. Must not be 078 * {@code null}. 079 * @param jwsAlgorithm The expected HMAC algorithm (HS256, HS384 or 080 * HS512) for the JWT assertion. Must be supported 081 * and not {@code null}. 082 * @param secret The secret. Must be at least 256-bits long. 083 * 084 * @return The JWT bearer assertion. 085 * 086 * @throws JOSEException If the client secret is too short, or HMAC 087 * computation failed. 088 */ 089 public static SignedJWT create(final JWTAssertionDetails details, 090 final JWSAlgorithm jwsAlgorithm, 091 final Secret secret) 092 throws JOSEException { 093 094 SignedJWT signedJWT = new SignedJWT(new JWSHeader(jwsAlgorithm), details.toJWTClaimsSet()); 095 signedJWT.sign(new MACSigner(secret.getValueBytes())); 096 return signedJWT; 097 } 098 099 100 /** 101 * Creates a new signed JWT bearer assertion. 102 * 103 * @param details The JWT bearer assertion details. Must not be 104 * {@code null}. 105 * @param jwsAlgorithm The expected RSA (RS256, RS384, RS512, PS256, 106 * PS384 or PS512) or EC (ES256, ES384, ES512) 107 * signature algorithm for the JWT assertion. Must 108 * be supported and not {@code null}. 109 * @param privateKey The signing private RSA or EC key. Must not be 110 * {@code null}. 111 * @param keyID Optional identifier for the key, to aid key 112 * selection on the recipient side. Recommended. 113 * {@code null} if not specified. 114 * @param x5c Optional X.509 certificate chain for the public 115 * key, {@code null} if not specified. 116 * @param x5t256 Optional X.509 certificate SHA-256 thumbprint, 117 * {@code null} if not specified. 118 * @param jcaProvider Optional specific JCA provider, {@code null} to 119 * use the default one. 120 * 121 * @return The JWT bearer assertion. 122 * 123 * @throws JOSEException If signing failed. 124 */ 125 public static SignedJWT create(final JWTAssertionDetails details, 126 final JWSAlgorithm jwsAlgorithm, 127 final PrivateKey privateKey, 128 final String keyID, 129 final List<Base64> x5c, 130 final Base64URL x5t256, 131 final Provider jcaProvider) 132 throws JOSEException { 133 134 SignedJWT signedJWT = new SignedJWT( 135 new JWSHeader.Builder(jwsAlgorithm) 136 .keyID(keyID) 137 .x509CertChain(x5c) 138 .x509CertSHA256Thumbprint(x5t256) 139 .build(), 140 details.toJWTClaimsSet()); 141 142 final JWSSigner signer; 143 if (RSASSASigner.SUPPORTED_ALGORITHMS.contains(jwsAlgorithm)) { 144 signer = new RSASSASigner(privateKey); 145 } else if (ECDSASigner.SUPPORTED_ALGORITHMS.contains(jwsAlgorithm)) { 146 Set<Curve> curves = Curve.forJWSAlgorithm(jwsAlgorithm); 147 if (curves.size() != 1) { 148 throw new JOSEException("Couldn't determine curve for JWS algorithm: " + jwsAlgorithm); 149 } 150 signer = new ECDSASigner(privateKey, curves.iterator().next()); 151 } else { 152 throw new JOSEException("Unsupported JWS algorithm: " + jwsAlgorithm); 153 } 154 155 if (jcaProvider != null) { 156 signer.getJCAContext().setProvider(jcaProvider); 157 } 158 159 signedJWT.sign(signer); 160 161 return signedJWT; 162 } 163 164 165 /** 166 * Creates a new RSA-signed JWT bearer assertion. 167 * 168 * @param details The JWT bearer assertion details. Must not be 169 * {@code null}. 170 * @param jwsAlgorithm The expected RSA signature algorithm (RS256, 171 * RS384, RS512, PS256, PS384 or PS512) for the 172 * JWT assertion. Must be supported and not 173 * {@code null}. 174 * @param rsaPrivateKey The RSA private key. Must not be {@code null}. 175 * @param keyID Optional identifier for the RSA key, to aid key 176 * selection on the recipient side. Recommended. 177 * {@code null} if not specified. 178 * @param jcaProvider Optional specific JCA provider, {@code null} to 179 * use the default one. 180 * 181 * @return The JWT bearer assertion. 182 * 183 * @throws JOSEException If RSA signing failed. 184 */ 185 @Deprecated 186 public static SignedJWT create(final JWTAssertionDetails details, 187 final JWSAlgorithm jwsAlgorithm, 188 final RSAPrivateKey rsaPrivateKey, 189 final String keyID, 190 final Provider jcaProvider) 191 throws JOSEException { 192 193 return create(details, jwsAlgorithm, rsaPrivateKey, keyID, null, null, jcaProvider); 194 } 195 196 197 /** 198 * Creates a new EC-signed JWT bearer assertion. 199 * 200 * @param details The JWT bearer assertion details. Must not be 201 * {@code null}. 202 * @param jwsAlgorithm The expected EC signature algorithm (ES256, 203 * ES384 or ES512) for the JWT assertion. Must be 204 * supported and not {@code null}. 205 * @param ecPrivateKey The EC private key. Must not be {@code null}. 206 * @param keyID Optional identifier for the EC key, to aid key 207 * selection on the recipient side. Recommended. 208 * {@code null} if not specified. 209 * @param jcaProvider Optional specific JCA provider, {@code null} to 210 * use the default one. 211 * 212 * @return The JWT bearer assertion. 213 * 214 * @throws JOSEException If RSA signing failed. 215 */ 216 @Deprecated 217 public static SignedJWT create(final JWTAssertionDetails details, 218 final JWSAlgorithm jwsAlgorithm, 219 final ECPrivateKey ecPrivateKey, 220 final String keyID, 221 final Provider jcaProvider) 222 throws JOSEException { 223 224 return create(details, jwsAlgorithm, ecPrivateKey, keyID, null, null, jcaProvider); 225 } 226 227 228 /** 229 * Prevents public instantiation. 230 */ 231 private JWTAssertionFactory() {} 232}