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 java.util.Collections; 022import java.util.LinkedHashSet; 023import java.util.Set; 024 025import com.nimbusds.jose.JOSEException; 026import com.nimbusds.jose.JWSAlgorithm; 027import com.nimbusds.jose.JWSSigner; 028import com.nimbusds.jose.crypto.ECDSASigner; 029import com.nimbusds.jose.crypto.Ed25519Signer; 030import com.nimbusds.jose.crypto.MACSigner; 031import com.nimbusds.jose.crypto.RSASSASigner; 032import com.nimbusds.jose.jca.JCAContext; 033import com.nimbusds.jose.jwk.*; 034import com.nimbusds.jose.produce.JWSSignerFactory; 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 2020-03-29 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 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) { 094 signer = new ECDSASigner((ECKey)key); 095 } else if (key instanceof OctetKeyPair) { 096 signer = new Ed25519Signer((OctetKeyPair)key); 097 } else { 098 throw new JOSEException("Unsupported JWK type: " + key); 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 (MACSigner.SUPPORTED_ALGORITHMS.contains(alg)) { 123 124 if (!(key instanceof OctetSequenceKey)) { 125 throw JWKException.expectedClass(OctetSequenceKey.class); 126 } 127 128 signer = new MACSigner((OctetSequenceKey)key); 129 } else if (RSASSASigner.SUPPORTED_ALGORITHMS.contains(alg)) { 130 131 if (!(key instanceof RSAKey)) { 132 throw JWKException.expectedClass(RSAKey.class); 133 } 134 135 signer = new RSASSASigner((RSAKey)key); 136 } else if (ECDSASigner.SUPPORTED_ALGORITHMS.contains(alg)) { 137 138 if (!(key instanceof ECKey)) { 139 throw JWKException.expectedClass(ECKey.class); 140 } 141 142 signer = new ECDSASigner((ECKey)key); 143 } else if (Ed25519Signer.SUPPORTED_ALGORITHMS.contains(alg)) { 144 145 if (!(key instanceof OctetKeyPair)) { 146 throw JWKException.expectedClass(OctetKeyPair.class); 147 } 148 149 signer = new Ed25519Signer((OctetKeyPair)key); 150 151 } else { 152 throw new JOSEException("Unsupported JWS algorithm: " + alg); 153 } 154 155 // Apply JCA context 156 signer.getJCAContext().setSecureRandom(jcaContext.getSecureRandom()); 157 signer.getJCAContext().setProvider(jcaContext.getProvider()); 158 159 return signer; 160 } 161}