001/* 002 * nimbus-jose-jwt 003 * 004 * Copyright 2012-2020, 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.factories; 019 020 021import com.nimbusds.jose.JOSEException; 022import com.nimbusds.jose.JWSAlgorithm; 023import com.nimbusds.jose.JWSSigner; 024import com.nimbusds.jose.crypto.ECDSASigner; 025import com.nimbusds.jose.crypto.Ed25519Signer; 026import com.nimbusds.jose.crypto.MACSigner; 027import com.nimbusds.jose.crypto.RSASSASigner; 028import com.nimbusds.jose.jca.JCAContext; 029import com.nimbusds.jose.jwk.*; 030import com.nimbusds.jose.produce.JWSSignerFactory; 031 032import java.util.Collections; 033import java.util.LinkedHashSet; 034import java.util.Set; 035 036/** 037 * A factory to create JWS signers from a JWK instance based on the 038 * key type. 039 * 040 * @author Justin Richer 041 * @since 2024-05-07 042 */ 043public class DefaultJWSSignerFactory implements JWSSignerFactory { 044 045 /** 046 * The JCA context. 047 */ 048 private final JCAContext jcaContext = new JCAContext(); 049 050 /** 051 * The supported JWS algorithms. 052 */ 053 public static final Set<JWSAlgorithm> SUPPORTED_ALGORITHMS; 054 055 056 static { 057 Set<JWSAlgorithm> algs = new LinkedHashSet<>(); 058 algs.addAll(MACSigner.SUPPORTED_ALGORITHMS); 059 algs.addAll(RSASSASigner.SUPPORTED_ALGORITHMS); 060 algs.addAll(ECDSASigner.SUPPORTED_ALGORITHMS); 061 algs.addAll(Ed25519Signer.SUPPORTED_ALGORITHMS); 062 SUPPORTED_ALGORITHMS = Collections.unmodifiableSet(algs); 063 } 064 065 @Override 066 public Set<JWSAlgorithm> supportedJWSAlgorithms() { 067 return SUPPORTED_ALGORITHMS; 068 } 069 070 @Override 071 public JCAContext getJCAContext() { 072 return jcaContext; 073 } 074 075 @Override 076 public JWSSigner createJWSSigner(final JWK key) throws JOSEException { 077 078 if (!key.isPrivate()) { // can't create a signer without the private key 079 throw JWKException.expectedPrivate(); 080 } 081 082 if (key.getKeyUse() != null && ! KeyUse.SIGNATURE.equals(key.getKeyUse())) { 083 throw new JWKException("The JWK use must be sig (signature) or unspecified"); 084 } 085 086 JWSSigner signer; 087 088 // base this just on the key type (+ curve) alone without the algorithm check 089 if (key instanceof OctetSequenceKey) { 090 signer = new MACSigner((OctetSequenceKey)key); 091 } else if (key instanceof RSAKey) { 092 signer = new RSASSASigner((RSAKey)key); 093 } else if (key instanceof ECKey && ECDSASigner.SUPPORTED_CURVES.contains(((ECKey) key).getCurve())) { 094 signer = new ECDSASigner((ECKey)key); 095 } else if (key instanceof OctetKeyPair && Ed25519Signer.SUPPORTED_CURVES.contains(((OctetKeyPair) key).getCurve())) { 096 signer = new Ed25519Signer((OctetKeyPair)key); 097 } else { 098 throw new JOSEException("Unsupported JWK type and / or curve"); 099 } 100 101 // Apply JCA context 102 signer.getJCAContext().setSecureRandom(jcaContext.getSecureRandom()); 103 signer.getJCAContext().setProvider(jcaContext.getProvider()); 104 105 return signer; 106 } 107 108 @Override 109 public JWSSigner createJWSSigner(final JWK key, final JWSAlgorithm alg) throws JOSEException { 110 111 if (!key.isPrivate()) { // can't create a signer without the private key 112 throw JWKException.expectedPrivate(); 113 } 114 115 if (key.getKeyUse() != null && ! KeyUse.SIGNATURE.equals(key.getKeyUse())) { 116 throw new JWKException("The JWK use must be sig (signature) or unspecified"); 117 } 118 119 JWSSigner signer; 120 121 122 if ( 123 MACSigner.SUPPORTED_ALGORITHMS.contains(alg) && 124 key instanceof OctetSequenceKey) { 125 126 signer = new MACSigner((OctetSequenceKey)key); 127 128 } else if ( 129 RSASSASigner.SUPPORTED_ALGORITHMS.contains(alg) && 130 key instanceof RSAKey) { 131 132 signer = new RSASSASigner((RSAKey)key); 133 134 } else if ( 135 ECDSASigner.SUPPORTED_ALGORITHMS.contains(alg) && 136 key instanceof ECKey && 137 ECDSASigner.SUPPORTED_CURVES.contains(((ECKey) key).getCurve())) { 138 139 signer = new ECDSASigner((ECKey)key); 140 141 } else if ( 142 Ed25519Signer.SUPPORTED_ALGORITHMS.contains(alg) && 143 key instanceof OctetKeyPair && 144 Ed25519Signer.SUPPORTED_CURVES.contains(((OctetKeyPair) key).getCurve())) { 145 146 signer = new Ed25519Signer((OctetKeyPair)key); 147 148 } else { 149 throw new JOSEException("Unsupported JWK type, JWK curve and / or JWS algorithm"); 150 } 151 152 // Apply JCA context 153 signer.getJCAContext().setSecureRandom(jcaContext.getSecureRandom()); 154 signer.getJCAContext().setProvider(jcaContext.getProvider()); 155 156 return signer; 157 } 158}